2 /* Copyright (c) 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006 by Arkkra Enterprises */
3 /* All rights reserved */
5 /* make the final pass through the main list, writing out the PostScript output
6 * for printing the music. This file contains most of the general print
7 * phase functions. Those that are associated with printing
8 * things from S_STAFF structs are mostly in prntdata.c.
9 * Tablature is printed via printtab.c.
10 * Additional print functions are in prntmisc.c and utils.c.
20 /* print only if flag is turned on. This allows printing selected pages */
21 static int Printflag = YES;
22 #define OUTP(x) if (Printflag==YES){(void)printf x;}
23 #define OUTPCH(x) if (Printflag == YES){putchar x;}
26 /* the PostScript commands */
29 #define O_LINEWIDTH (3)
32 #define O_SHOWPAGE (6)
37 #define O_LINE (11) /* lineto stroke */
39 #define O_BRACKET (13)
40 #define O_ENDDOTTED (14)
44 #define O_RESTORE (18)
48 #define O_NEWPATH (22)
49 #define O_CLOSEPATH (23)
51 #define O_GRESTORE (25)
56 #define O_TRANSLATE (30)
58 #define O_WIDTHSHOW (32)
66 * For debugging, it can be useful to display the "bounding box"
67 * which is stored in the coordinate arrays of various entities.
68 * This list tells which entities have coords.
69 * These must match the indices in the Bbox_list array.
75 #define BB_BLOCKHEAD 4
79 /* Macros to turn on display of a coord type and to check if it is on */
80 #define BB_SET(x) Do_bbox |= (1<<x)
81 #define BB_IS_SET(x) (Do_bbox & (1<<x))
83 /* This struct holds information about how to display a coord bounding box.
84 * We use the environment variable MUP_BB to turn on this displaying.
85 * For now, we hard-code what color/dashing to use. MUP_BB could optionally
86 * contain color info some day, but that seems like overkill flexibility.
89 char id; /* character in $MUP_BB that says to draw these */
90 char red; /* per cent of this color to use when drawing */
93 char dash_on; /* for setdash */
96 { 'b', 100, 50, 0, 5, 2 }, /* BAR */
97 { 'c', 0, 80, 0, 5, 2 }, /* CHORD */
98 { 'f', 50, 50, 0, 0, 0 }, /* FEED */
99 { 'g', 100, 0, 0, 0, 0 }, /* GRPSYL */
100 { 'h', 0, 80, 50, 0, 0 }, /* headings, etc */
101 { 'n', 0, 0, 100, 0, 0 }, /* NOTE */
102 { 's', 0, 50, 80, 5, 3 }, /* STAFF */
103 { 'u', 100, 0, 100, 5, 2 } /* STUFF */
105 static short Do_bbox = 0;
108 /* if memory is scarce, we do each font in a separate save/restore context.
109 * Need flag to keep track of whether we are in one of those */
110 static int Did_save = NO;
113 /* for header, to indicate when output file was generated */
114 static char *Dayofweek[] = {
115 "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat" };
116 static char *Month[] = {
117 "Jan", "Feb", "Mar", "Apr", "May", "Jun",
118 "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" };
120 static int Pagesprinted = 0; /* number of pages actually printed */
121 static int Feednumber; /* how many pagefeeds we've handled */
124 static struct STAFF *Last_staff; /* point to last STAFF we saw, to
125 * save having to back up to it
126 * later to check if it was a
129 static int Last_linetype = -1; /* keep track of last type. If same,
130 * this time, no reason to output */
131 static float Last_staffscale; /* Change in staffscale also changes
132 * line width, so have to remember it */
133 static short Doing_dotted = NO; /* keep track of whether last line
134 * was dotted. If it was, but current
135 * one isn't, need to tell PostScript */
136 static double x1a, x2a, ya; /* x and y adjustments */
139 static int Landscape; /* how much to translate for landscape
140 * mode, or 0 if not in landscape */
142 /* static functions */
143 static void init4print P((void));
144 static void page1setup P((void));
145 static int use_landscape P((double pgwidth, double pgheight));
146 static void setup_user_fonts P((void));
148 static void setup_extended_fonts P((void));
150 static void pr_line P((struct LINE *line_p, char *fname, int lineno));
151 static void dr_line P((double x1, double y1, double x2, double y2, int ltype));
152 static void pr_curve P((struct CURVE *curve_p, char *fname, int lineno));
153 static void outp_muschar P((double x, double y, int ch, int size, int font));
154 static void pr_ital_muschar P((double x, double y, int ch, int size, int font));
155 static void pr_bar P((struct MAINLL *mll_p, double x, int is_pseudobar));
156 static void pr_bar_range P((struct BAR *bar_p, int topstaff,
157 int botstaff, double x, int next_is_restart,
158 struct MAINLL *mll_p));
159 static void draw_bar P((int bartype, int linetype, double x, double y1,
161 static void pr_repeat_dots P((int bartype, int staff, double x));
162 static void do_rdots P((double x, double y, double topoffset, double bottomosffset));
163 static void pr_reh P((struct MAINLL *mll_p));
164 static void pr_box P((double x, double y, double boxheight, double boxwidth));
165 static void pr_topbot P((struct BLOCKHEAD *blockhead_p, double y));
166 static void pr_restarts P((struct MAINLL *mll_p, double y1, double y2,
167 int need_vert_line));
168 static void outint P((int val));
169 static void pr_wstring P((double x, double y, char *string, int justify,
170 double fullwidth, char * fname, int lineno));
171 static void outstring P((double x, double y, double fullwidth, char *string,
172 char * fname, int lineno));
173 static int begin_string P((int in_string));
174 static int end_string P((int in_string, double space_adjust));
175 static void outop P((int op));
176 static void pr_headfoot P((struct MAINLL *mll_p));
177 static void to_next_page P((struct MAINLL *mll_p));
178 static void pr_print P((struct PRINTDATA *printdata_p));
179 static double pr_keysig P((int staffno, int sharps, int naturals, double x,
181 static void draw_keysig P((int muschar, int symbols, double x,
182 double y, int *table, int offset, int skip));
183 static double pr_timesig P((int staffno, double x, int multnum,
185 static double tsjam P((int num));
186 static void pr_tsnum P((double x, double y, char *str, double jam));
187 static void draw_circle P((double x, double y, double radius));
188 static void do_scale P((double xscale, double yscale));
189 static void pr_font P((int font, int size));
190 static void prfontname P((int font));
191 static void split_a_string P((double x, double y, char *string, int justify,
192 double fullwidth, char *fname, int lineno));
193 static void j_outstring P((double x, double y, char *string, int justify,
194 double fullwidth, char *fname, int lineno));
195 static void set_staff_y P((struct MAINLL *main_p));
196 static void pr_meas_num P((int staffno, double x));
197 static void setscale P((void));
198 static void show_coord P((float *coord_p, int index));
199 static void prep_bbox P((void));
200 static void show_bounding_boxes P((struct MAINLL *mll_p));
203 /* main function of print phase. Walk through main list,
204 * printing things as we go */
210 struct MAINLL *mll_p; /* to walk through list */
214 debug(256, "print_music");
217 /* initialize for printing */
220 /* walk down the list, printing as we go */
221 for (mll_p = Mainllhc_p; mll_p != (struct MAINLL *) NULL;
222 mll_p = mll_p->next) {
225 /* in debug mode, print out Postscript comments
226 * to make it easier to map output back to input */
227 OUTP(("%% %s\n", stype_name(mll_p->str)));
230 /* tell output program what the user input line was */
231 /* STAFF structs have lots of things hung off them that
232 * could come from different input lines, so do that
234 if (mll_p->str != S_STAFF && mll_p->inputlineno > 0) {
235 pr_linenum(mll_p->inputfile, mll_p->inputlineno);
238 /* call appropriate function(s) based on type */
242 /* assign the values from the SSV and reset
243 * the _win parameters */
244 asgnssv(mll_p->u.ssv_p);
245 set_win(PGHEIGHT - EFF_TOPMARGIN, EFF_BOTMARGIN,
246 PGWIDTH - eff_rightmargin((struct MAINLL *)0),
247 eff_leftmargin((struct MAINLL *)0));
251 OUTP(("%% staff %d\n", mll_p->u.staff_p->staffno));
253 set_staffscale(mll_p->u.staff_p->staffno);
256 Curr_font = FONT_UNKNOWN;
257 Curr_size = DFLT_SIZE;
258 Last_staff = mll_p->u.staff_p;
262 pr_bar(mll_p, (double)mll_p->u.bar_p->c[AX],
264 /* reset the staffscale to its scorewide
270 /* nothing to do here--we print notes when we
271 * hit the S_STAFF structs */
275 pr_print(mll_p->u.prhead_p->printdata_p);
279 pr_line(mll_p->u.line_p, mll_p->inputfile,
284 pr_curve(mll_p->u.curve_p, mll_p->inputfile,
294 (void) pr_clefsig(mll_p, mll_p->u.clefsig_p, YES);
295 /* have to do rehearsal marks, because we only
296 * print a pseudo-bar if it is visible */
297 if (mll_p->u.clefsig_p->bar_p != (struct BAR *) 0) {
303 if (mll_p->prev == 0 || mll_p->prev->str != S_FEED) {
304 pfatal("blockhead without preceeding feed");
306 feed_p = mll_p->prev->u.feed_p;
307 set_win_coord(mll_p->u.blockhead_p->c);
308 set_win(feed_p->c[AN], feed_p->c[AS],
309 feed_p->c[AE], feed_p->c[AW]);
310 set_cur(mll_p->prev->u.feed_p->c[AW],
311 mll_p->prev->u.feed_p->c[AN]);
312 pr_print(mll_p->u.blockhead_p->printdata_p);
316 pfatal("unknown item in main list");
321 /* do grid atend things if necessary */
322 if (Atend_info.grids_used > 0) {
323 if (Atend_info.separate_page == YES) {
324 /* The only MUP_BB thing that matters on grids at end
325 * page is header/footer, and because of the order
326 * in which things are done in pr_atend()
327 * (i.e., when top/bottom are set relative to when the
328 * MUP_BB printing code is called),
329 * it's hard to find a way
330 * to make that work without breaking something else.
331 * So since grids at end is such a rare case,
332 * and MUP_BB is just for debugging,
333 * we just turn it off. */
339 /* do final stuff for last page */
340 pr_headfoot(Mainlltc_p);
344 /* do the things for starting a new page */
348 struct MAINLL *mll_p;
357 /* print final trailer */
363 int f; /* font index */
366 printf("%%%%Trailer\n");
367 printf("%%%%DocumentFonts: ");
368 for (f = 1; f < MAXFONTS; f++) {
369 if (Font_used[f] == YES) {
374 printf("\n%%%%Pages: %d\n", Score.panelsperpage == 1 ? Pagesprinted :
375 ((Pagesprinted + 1) / 2) );
379 /* initialize things for print pass through main list */
385 struct tm *timeinfo_p;
387 struct MAINLL *mll_p;
389 static int first_time = YES;
391 if (first_time == NO) {
397 /* initialize the SSV data */
400 printf("%%!PS-Adobe-1.0\n");
401 printf("%%%%Creator: Mup\n");
402 printf("%%%%Title: music: %s from %s\n", Outfilename, Curr_filename);
403 clockinfo = time((time_t *)0);
404 timeinfo_p = localtime(&clockinfo);
405 printf("%%%%CreationDate: %s %s %d %d:%d:%d %d\n",
406 Dayofweek[timeinfo_p->tm_wday],
407 Month[timeinfo_p->tm_mon], timeinfo_p->tm_mday,
408 timeinfo_p->tm_hour, timeinfo_p->tm_min,
409 timeinfo_p->tm_sec, 1900 + timeinfo_p->tm_year);
410 printf("%%%%Pages: (atend)\n");
411 printf("%%%%DocumentFonts: (atend)\n");
412 /* we need to know the value of panelsperpage before setting up the
413 * first page, as well as the pagewidth and pageheight,
414 * so need to peek into main list up till the first non-SSV
416 for (mll_p = Mainllhc_p; mll_p != (struct MAINLL *) NULL;
417 mll_p = mll_p->next) {
418 if (mll_p->str == S_SSV) {
419 asgnssv(mll_p->u.ssv_p);
422 /* as soon as we hit something other than SSV,
423 * we're past any page size changes */
427 bbox_format = "%%%%BoundingBox: 0 0 %d %d\n";
428 if (Score.panelsperpage == 2) {
429 /* have to compensate for the fact that our page width/height
430 * internally are that of the panel, but here we need the
431 * physical paper size */
432 printf(bbox_format, (int) (Score.pageheight * PPI),
433 (int) (Score.pagewidth * 2.0 * PPI));
435 else if ((Landscape = use_landscape(Score.pagewidth, Score.pageheight))
437 printf(bbox_format, (int) (Score.pageheight * PPI),
438 (int) (Score.pagewidth * PPI));
441 printf(bbox_format, (int) (Score.pagewidth * PPI),
442 (int) (Score.pageheight * PPI));
444 printf("%%%%EndComments\n");
446 printf("/flagsep %.2f 300 mul def\t %% %.2f stepsizes\n",
447 FLAGSEP / STEPSIZE, FLAGSEP / STEPSIZE);
448 srand((unsigned)timeinfo_p->tm_sec);
449 (void) printf("/scv %d def ", ((rand() & 0x27d) << 8) | 4);
450 (void) printf("/sf 962 string def\n");
451 (void) printf("/fa {/p 0 def /chr exch -3 bitshift 127 and def {sf exch p add dup /p exch def chr put} forall} def\n");
452 (void) printf("[ 74 62 70 54 29 55 36 37 19 26 45 40 41 50 45 52 19 73 11 68 ] 1567304784 fa\n");
453 (void) printf("[ 961 ] 1341740116 fa\n");
454 (void) printf("[ 12 4 5 4 4 2 4 3 3 7 7 3 5 5 4 5 4 2 5 3 ] 1969419526 fa\n");
455 (void) printf("[ 96 4 4 3 2 4 11 2 6 23 13 16 8 3 28 13 8 3 6 11 ] 387152134 fa\n");
456 (void) printf("[ 268 4 13 12 5 4 4 5 4 5 3 2 4 3 4 8 3 3 9 2 ] 305899779 fa\n");
457 (void) printf("[ 369 3 4 9 3 3 9 2 4 3 4 7 4 4 4 9 5 3 5 4 ] 477458695 fa\n");
458 (void) printf("[ 498 4 36 4 37 4 42 4 4 37 4 4 35 4 4 5 13 3 4 4 ] 1130513667 fa\n");
459 (void) printf("[ 759 3 5 33 4 5 9 29 5 4 3 5 4 4 5 4 4 5 4 3 ] 1205319942 fa\n");
460 (void) printf("[ 902 8 4 2 3 4 3 4 4 3 2 3 9 ] 1708988675 fa\n");
461 (void) printf("[ 468 6 4 10 3 30 5 3 24 40 4 3 3 3 3 8 23 1 1 1 ] 123455756 fa\n");
462 (void) printf("[ 664 23 4 2 13 66 4 5 9 ] 2061720845 fa\n");
463 (void) printf("[ 795 ] 1622189328 fa\n");
464 (void) printf("[ 463 45 40 41 50 45 84 ] 304180545 fa\n");
465 (void) printf("[ 494 40 41 49 45 43 84 ] 251711819 fa\n");
466 (void) printf("[ 149 203 37 144 ] 358262127 fa\n");
467 (void) printf("[ 456 142 52 ] 95949173 fa\n");
468 (void) printf("[ 0 13 13 10 65 36 6 26 38 17 13 53 4 13 13 25 36 183 7 140 ] 1751712121 fa\n");
469 (void) printf("[ 839 5 13 12 13 13 48 ] 1943250302 fa\n");
470 (void) printf("[ 30 164 254 7 42 4 36 4 18 1 18 4 46 3 1 41 4 39 4 41 ] 499619205 fa\n");
471 (void) printf("[ 798 1 3 1 ] 1277775234 fa\n");
472 (void) printf("[ 76 32 135 79 99 8 246 43 30 160 ] 734015880 fa\n");
473 (void) printf("[ 265 70 36 12 25 87 4 36 4 37 4 46 4 41 43 83 4 83 41 3 ] 1546658194 fa\n");
474 (void) printf("[ 193 49 180 8 17 134 ] 831070621 fa\n");
475 (void) printf("[ 353 366 ] 1033403809 fa\n");
476 (void) printf("[ 266 1 190 39 40 41 50 45 43 45 ] 1758436783 fa\n");
477 (void) printf("[ 423 8 109 ] 508918194 fa\n");
478 (void) printf("[ 328 6 30 6 31 6 269 ] 212071871 fa\n");
479 (void) printf("[ 390 357 2 ] 1671244225 fa\n");
480 (void) printf("[ 500 ] 347047368 fa\n");
481 (void) printf("[ 558 ] 1276946910 fa\n");
482 (void) printf("[ 651 ] 2109048312 fa\n");
483 (void) printf("[ 644 ] 1914352160 fa\n");
484 (void) printf("[ 520 ] 471204394 fa\n");
485 (void) printf("[ 512 5 2 ] 1930983991 fa\n");
486 (void) printf("[ 665 ] 154021439 fa\n");
487 (void) printf("[ 513 ] 777103941 fa\n");
488 (void) printf("[ 514 ] 260959830 fa\n");
489 (void) printf("[ 530 239 ] 1284535922 fa\n");
490 (void) printf("[ 510 ] 1982423675 fa\n");
491 (void) printf("[ 150 ] 1969948305 fa\n");
492 (void) printf("[ 511 7 134 ] 1407991454 fa\n");
493 (void) printf("[ 144 371 ] 1896661664 fa\n");
494 (void) printf("[ 464 52 ] 1444653737 fa\n");
495 (void) printf("[ 509 81 ] 1712172720 fa\n");
496 (void) printf("[ 110 11 32 24 22 18 40 12 54 7 17 19 18 19 22 13 377 94 9 11 ] 889612 fa\n");
497 (void) printf("[ 954 ] 1802916616 fa\n");
498 (void) printf("[ 80 146 51 78 37 84 8 8 73 5 44 45 33 9 73 9 130 9 11 12 ] 1808121621 fa\n");
499 (void) printf("[ 19 42 3 22 8 82 63 23 25 13 8 5 176 248 40 73 12 13 13 12 ] 1752602397 fa\n");
500 (void) printf("[ 22 10 37 42 1 2 19 26 6 38 17 13 38 11 21 13 16 9 27 9 ] 1598682919 fa\n");
501 (void) printf("[ 405 9 13 46 49 50 50 213 18 12 13 13 12 45 10 ] 160257827 fa\n");
502 (void) printf("[ 1 8 8 6 10 10 16 11 14 8 23 19 13 19 13 7 15 3 9 8 ] 882894639 fa\n");
503 (void) printf("[ 234 40 9 15 6 7 6 25 36 37 19 6 47 16 40 41 50 45 43 6 ] 185215791 fa\n");
504 (void) printf("[ 733 19 37 16 12 13 3 3 12 6 6 6 7 6 7 6 6 6 45 10 ] 1706915629 fa\n");
505 (void) printf("[ 24 10 37 45 2 17 5 1 15 4 7 5 8 8 17 17 13 11 8 26 ] 1713964852 fa\n");
506 (void) printf("[ 284 21 13 25 18 18 19 18 28 1 7 28 2 4 106 24 3 2 32 36 ] 1218620208 fa\n");
507 (void) printf("[ 695 62 1 7 13 1 7 2 37 4 8 5 13 12 13 13 12 45 5 1 ] 1317868340 fa\n");
508 (void) printf("[ 960 ] 75399990 fa\n");
509 (void) printf("[ 45 9 155 6 245 68 21 98 60 109 ] 1430691640 fa\n");
510 (void) printf("[ 20 27 15 25 8 33 173 13 45 37 83 170 5 34 8 115 40 12 13 13 ] 841629509 fa\n");
511 (void) printf("[ 901 ] 422446918 fa\n");
512 (void) printf("[ 27 25 37 13 3 40 12 73 49 77 4 33 4 68 89 219 21 27 3 4 ] 560155470 fa\n");
513 (void) printf("[ 466 6 135 41 7 6 36 6 89 ] 803193686 fa\n");
514 (void) printf("[ 42 80 1 55 80 1 80 36 37 155 1 263 40 65 ] 189315943 fa\n");
515 (void) printf("[ 6 31 36 9 43 21 6 185 36 37 210 ] 1031359337 fa\n");
516 (void) printf("[ 44 9 101 4 4 20 8 80 3 23 30 5 19 17 20 17 15 7 7 36 ] 586694517 fa\n");
517 (void) printf("[ 552 22 20 16 3 55 42 31 10 33 ] 343336822 fa\n");
518 (void) printf("[ 7 4 54 54 10 22 10 20 8 8 53 5 226 12 115 38 17 42 26 13 ] 1808462718 fa\n");
519 (void) printf("[ 780 32 ] 847653755 fa\n");
520 (void) printf("[ 3 63 31 408 18 4 18 6 22 13 15 3 32 9 17 4 15 5 18 4 ] 1627872128 fa\n");
521 (void) printf("[ 724 83 7 ] 1643402114 fa\n");
522 (void) printf("[ 228 296 8 25 39 16 159 14 34 ] 670118796 fa\n");
523 (void) printf("[ 2 2 47 69 19 34 23 20 35 5 187 10 51 2 38 2 39 2 48 2 ] 888380310 fa\n");
524 (void) printf("[ 680 2 41 2 2 5 13 11 10 40 2 50 80 ] 1392580498 fa\n");
525 (void) printf("[ 14 25 10 7 22 49 21 22 1 4 10 23 4 13 15 5 16 15 12 3 ] 2114772893 fa\n");
526 (void) printf("[ 295 30 24 9 28 9 23 19 13 1 8 24 67 16 3 30 3 3 53 9 ] 453068702 fa\n");
527 (void) printf("[ 694 6 9 20 11 23 1 23 23 22 8 5 1 24 41 9 11 4 5 1 ] 1393470366 fa\n");
528 (void) printf("[ 944 8 ] 1770206109 fa\n");
529 (void) printf("[ 10 5 25 6 4 7 42 39 25 20 4 4 7 2 14 17 126 5 32 5 ] 113705892 fa\n");
530 (void) printf("[ 442 25 4 6 114 27 38 42 32 25 20 47 19 112 ] 998588323 fa\n");
531 (void) printf("[ 79 19 131 109 36 37 74 70 1 59 8 34 3 25 5 9 3 80 11 27 ] 1221405612 fa\n");
532 (void) printf("[ 912 9 11 ] 273962927 fa\n");
533 (void) printf("[ 8 230 25 23 6 17 130 31 61 64 16 127 32 ] 1881483187 fa\n");
534 (void) printf("[ 130 683 ] 1406620603 fa\n");
535 (void) printf("[ 18 10 32 25 5 3 10 3 143 50 13 9 61 93 86 1 1 180 48 58 ] 1980878788 fa\n");
536 (void) printf("[ 861 13 9 4 12 8 17 3 ] 1447963591 fa\n");
537 (void) printf("[ 67 143 8 128 115 435 19 2 ] 477757388 fa\n");
538 (void) printf("[ 490 35 ] 1151262673 fa\n");
539 (void) printf("[ 5 70 67 32 37 16 14 7 27 18 142 301 17 90 103 ] 1523362782 fa\n");
540 (void) printf("[ 117 14 33 38 17 13 20 26 3 453 89 3 8 113 10 ] 1908448236 fa\n");
541 (void) printf("sf cvx exec\n");
545 setup_extended_fonts();
547 printf("%%%%EndProlog\n");
549 /* init for first page */
554 /* set thing up to print the first page */
562 to_next_page(Mainllhc_p);
564 /* Arrange to start at beginning of main list */
567 /* start the cursor at the top left corner of page */
568 set_cur(0.0, PGHEIGHT);
571 Ped_snapshot[0] = NO;
576 /* table of standard paper sizes, to be used to see if user specified
577 * a landscape version of a standard size */
581 } Paper_size_table[] = {
582 { 612, 792 }, /* letter */
583 { 540, 720}, /* note */
584 { 612, 1008}, /* legal */
585 { 595, 842}, /* a4 */
586 { 421, 595}, /* a5 */
587 { 297, 421}, /* a6 */
588 { 612, 936}, /* flsa */
589 { 396, 612}, /* halfletter */
593 /* how many points away from an exact match to consider a match. This is big
594 * enough so that user can be off by a little and still get the desired
595 * results, yet not so big as to give false matches. */
601 /* given a paper size, determine if the paper
602 * size appears to be the landscape version of a standard paper size.
603 * If so, return the page height in points, otherwise return 0.
604 * It return this rather than just a boolean
605 * since page height is needed for translate amount.
609 use_landscape(pgwidth, pgheight)
611 double pgwidth; /* page width in inches */
612 double pgheight; /* page height in inches */
615 int pts_width, pts_height; /* width and height in points */
619 /* convert dimension to points */
620 pts_width = (int) (pgwidth * PPI);
621 pts_height = (int) (pgheight * PPI);
623 /* for each paper size table entry, see if by interchanging the
624 * width and height we would end up with something within FUZZ
625 * points of matching a landscape mode paper size */
626 for (i = 0; Paper_size_table[i].width != 0; i++) {
627 if (pts_width > Paper_size_table[i].height - FUZZ &&
628 pts_width < Paper_size_table[i].height + FUZZ &&
629 pts_height > Paper_size_table[i].width - FUZZ &&
630 pts_height < Paper_size_table[i].width + FUZZ) {
640 /* for any user-defined fonts, if there was any PostScript that needs to
641 * be output in order to use the font, output that.
651 for (f = 0; f < MAXFONTS; f++) {
652 if (Fontinfo[f].fontfile != (FILE *) 0) {
653 while (fgets(buffer, BUFSIZ, Fontinfo[f].fontfile)
655 printf("%s", buffer);
657 fclose(Fontinfo[f].fontfile);
665 /* for each extended character set font that was used somewhere, output
666 * the PostScript to get that font set up so that is can be used.
670 setup_extended_fonts()
673 int i; /* font index */
674 int have_extended; /* YES if extended character set was used
675 * somewhere, and thus we have to output
676 * PostScript to allow using the set */
679 /* First see if there are any extended characters used at all.
680 * If not, we don't have to do anything more here */
682 for (i = FONT_TR; i <= EXT_FONT_OFFSET; i++) {
683 if (Font_used[i + EXT_FONT_OFFSET] == YES) {
689 if (have_extended == NO) {
693 /* first call the PostScript function to set up the encoding
694 * array for the extended character set */
695 printf("\n%% set up extended character set fonts\n");
696 printf("makeExtEncoding\n");
698 /* now for each extended character set font that was actually used
699 * somewhere, call the PostScript function to set up that font,
700 * based on the font from which it is derived */
701 for (i = FONT_TR; i <= EXT_FONT_OFFSET; i++) {
702 if (Font_used[i + EXT_FONT_OFFSET] == YES) {
703 /* arguments are the name of the extended font
704 * and the name of the base font from which it
706 prfontname(i + EXT_FONT_OFFSET);
708 printf("makeExtendedFont\n");
715 /* given a LINE struct, output commands to draw a line */
718 pr_line(line_p, fname, lineno)
720 struct LINE *line_p; /* info about what kind of line to draw and where */
721 char *fname; /* file name for error messages */
722 int lineno; /* line number for error messages */
725 double x1, y1; /* beginning of line */
726 double x2, y2; /* end of line */
728 x1 = inpc_x( &(line_p->start), fname, lineno);
729 y1 = inpc_y( &(line_p->start), fname, lineno);
730 x2 = inpc_x( &(line_p->end), fname, lineno);
731 y2 = inpc_y( &(line_p->end), fname, lineno);
733 /* If there is a string associated with the line,
736 if (line_p->string != 0) {
737 double line_len; /* length of line in LINE struct */
738 double str_x, str_y; /* where string starts */
740 /* First find length of line. */
741 line_len = sqrt(SQUARED(x2 - x1) + SQUARED(y2 - y1));
743 line_len = -line_len;
746 /* For now, pretend the line is horizontal, starting
747 * at (x1,y1). The horizontal middle of the string should then
748 * be at the midpoint of the line, and the left edge of the
749 * string should be half the string width left of that.
750 * The vertical is a STEPSIZE above the line.
752 str_x = (line_len / 2.0) - (strwidth(line_p->string) / 2.0);
753 str_y = STEPSIZE + strdescent(line_p->string);
755 /* move effective origin of coordinate system to (x1,y1),
756 * then rotate by the appropriate angle and print string.
762 /* calculate angle. If vertical line or nearly so,
763 * avoid division by zero */
764 if (fabs(x2 - x1) < .001) {
768 OUTP(("%.1f ", atan( (y2 - y1) / (x2 - x1) ) * 180.0 / PI));
772 pr_string(str_x, str_y, line_p->string, J_LEFT, 0, -1);
776 /* wavy lines are special case */
777 if (line_p->linetype == L_WAVY) {
778 draw_wavy(x1, y1, x2, y2);
782 /* set line width to specified width and type, then draw the line */
783 do_linetype(line_p->linetype);
784 draw_line (x1, y1, x2, y2);
786 /* make sure line type gets set back to solid */
787 if (line_p->linetype == L_DASHED || line_p->linetype == L_DOTTED) {
788 do_linetype(L_NORMAL);
793 /* generate PostScript command to tell what kind of line to draw */
798 int ltype; /* L_WIDE, L_NORMAL, etc */
801 if (Last_linetype == ltype && Last_staffscale == Staffscale) {
802 /* same as last time, no need to tell the printer again */
806 /* output command for proper width/type of line */
810 OUTP(("%4.2f ", W_WIDE * Staffscale));
815 OUTP(("%4.2f ", W_NORMAL * Staffscale));
820 OUTP(("%4.2f ", W_MEDIUM * Staffscale));
825 OUTP(("%4.2f ", Staffscale));
832 OUTP(("%4.2f ", Staffscale));
839 pfatal("unknown line type");
843 /* remember current line type */
844 Last_linetype = ltype;
845 Last_staffscale = Staffscale;
847 /* if was doing dotting but not anymore, tell PostScript */
848 if (Doing_dotted && (ltype != L_DOTTED) && (ltype != L_DASHED)) {
855 /* output commands for drawing a line. Resulting output is:
856 * x1 y1 moveto x2 y2 lineto stroke */
859 draw_line(x1, y1, x2, y2)
861 double x1, y1; /* draw line from here */
862 double x2, y2; /* to here */
865 dr_line( (double) x1, (double) y1, (double) x2, (double) y2, O_LINE);
869 /* output commands to draw a line whose width is proportional to the given
873 draw_prop_line(x1, y1, x2, y2, size, ltype)
875 double x1, y1; /* draw line from here */
876 double x2, y2; /* to here */
877 int size; /* make width proportional to this */
878 int ltype; /* O_LINE, etc */
881 /* temporarily change the line width, then draw the line */
883 OUTP(("%.2f ", (double) size * 0.065 * Staffscale));
885 dr_line(x1, y1, x2, y2, O_LINE);
890 /* draw a wavy line. Resulting output is:
891 * x1 y1 moveto x2 y2 wavy */
894 draw_wavy(x1, y1, x2, y2)
897 double y1; /* draw wavy line from x1,y1 */
899 double y2; /* to x2, y2 */
902 dr_line((double) x1, (double) y1, (double) x2, (double) y2, O_WAVY);
906 /* actually draw line. Common function for drawing regular or wavy lines */
909 dr_line(x1, y1, x2, y2, ltype)
912 double y1; /* draw line from x1,y1 */
914 double y2; /* to x2,y2 */
915 int ltype; /* O_LINE, etc */
919 /* output coordinates */
928 /* current location is where line ended */
933 /* output commands to draw a curve */
936 pr_curve(curve_p, fname, lineno)
938 struct CURVE *curve_p; /* which curve */
939 char *fname; /* file name for error messages */
940 int lineno; /* line number for error messages */
943 struct INPCOORD *inpcoord_p;
945 float *xlist, *ylist;
946 float cwid; /* curve width */
947 int taper; /* YES or NO */
950 /* pr_allcurve() expects lists of X and Y coordinates, so
951 * get some space for those lists, and fill them in.
952 * Call pr_allcurve() to print the curve, then free the lists */
953 MALLOCA(float, xlist, curve_p->ncoord);
954 MALLOCA(float, ylist, curve_p->ncoord);
955 for (n = 0; n < curve_p->ncoord; n++) {
956 inpcoord_p = &(curve_p->coordlist[n]);
957 xlist[n] = inpc_x(inpcoord_p, fname, lineno);
958 ylist[n] = inpc_y(inpcoord_p, fname, lineno);
960 switch(curve_p->curvetype) {
962 cwid = W_NORMAL / PPI;
966 cwid = W_MEDIUM / PPI;
976 do_linetype(L_DASHED);
981 do_linetype(L_DOTTED);
984 pfatal("unknown curve type");
988 /* adjust for current staff scaling */
991 pr_allcurve(xlist, ylist, curve_p->ncoord, cwid, taper);
994 /* make sure line type gets set back to solid */
995 if (curve_p->curvetype == L_DASHED || curve_p->curvetype == L_DOTTED) {
996 do_linetype(L_NORMAL);
1001 /* functions to do common PostScript things */
1029 do_curveto(x1, y1, x2, y2, x3, y3)
1074 /* output a PostScript scale command */
1077 do_scale(xscale, yscale)
1079 double xscale, yscale;
1082 OUTP(("%0.6f %0.6f ", xscale, yscale));
1086 /* print a white box with the corners given */
1089 do_whitebox(x1, y1, x2, y2)
1099 OUTP(("whitebox\n"));
1103 /* output PostScript to draw a guitar grid */
1106 do_grid(x, y, space, grid_p, staff)
1110 double space; /* distance between lines of the grid */
1111 struct GRID *grid_p;
1116 int fret, fretnum, numvert;
1123 gridinfo(grid_p, staff, &fret, &fretnum, &numvert, &topfret);
1128 /* the curve ends */
1129 outint(grid_p->curvel);
1130 outint(grid_p->curver);
1132 /* fret value for each string in a PostScript array */
1134 for (s = 0; s < grid_p->numstr; s++) {
1135 if (grid_p->positions[s] <= 0) {
1136 outint(grid_p->positions[s]);
1139 outint(grid_p->positions[s] - topfret);
1146 /* output commands for printing one music character */
1149 pr_muschar(x, y, ch, size, font)
1151 float x, y; /* where to print */
1152 int ch; /* which music character to print */
1154 int font; /* FONT_MUSIC* */
1157 outp_muschar(x, y, ch, size, font);
1159 /* x of music char is in middle, so set current to right edge */
1160 size = adj_size(size, Staffscale, (char *) 0, -1);
1161 set_cur(x + width(font, size, ch) / 2.0, y);
1165 /* Output PostScript to print a music character. Common part for
1166 * normal and italic versions of the character. */
1169 outp_muschar(x, y, ch, size, font)
1178 /* tell where to print it */
1179 outcoord( (double) x);
1180 outcoord( (double) y);
1182 if (size == DFLT_SIZE) {
1183 scaling = Staffscale;
1186 scaling = (double) size * Staffscale / (double) DFLT_SIZE;
1188 OUTP(("%f ", scaling));
1190 /* output the symbolic name of the music character */
1191 OUTP(("%s\n", mc_num2name(ch, font)));
1195 /* Print an italic music character. We do this by constructing an
1196 * appropriate PostScript transform matrix and then printing the character.
1197 * The transform matrix takes the rectangle that bounds the character,
1198 * widens it slightly, and and turns it into a parallelogram
1199 * slanted by 15 degrees.
1200 * ---------- ---------
1203 * ---------- --------
1207 pr_ital_muschar(x, y, ch, size, font)
1209 double x, y; /* where to print */
1210 int ch; /* which music character to print */
1212 int font; /* MUSIC_FONT* */
1215 float chwidth, chheight;
1216 float adj; /* distance top left is moved to get slant */
1217 float inc; /* increment on width */
1218 float a, c; /* for transform equation x' = ax + cy + t */
1222 eff_size = adj_size(size, Staffscale, (char *) 0, -1);
1223 chheight = height(font, eff_size, ch);
1224 chwidth = width(font, eff_size, ch);
1225 /* Widen some so doesn't look so cramped. This may
1226 * encroach on neighboring characters, but if they are italic
1227 * too--which they probably are--they probably slant enough
1228 * to stay out of the way. */
1229 inc = MIN(chwidth, chheight * 0.8) / 4.0;
1231 /* we want to slant by 15 degrees, so use tangent of 15 degrees */
1232 adj = chheight * 0.27;
1233 /* if character is really narrow, don't slant so much--
1234 * don't squeeze character to less than half its original width */
1235 if (adj > chwidth / 2.0) {
1236 adj = chwidth / 2.0;
1239 /* Temporarily change the transform matrix.
1240 * The y value is unchanged by the transform.
1243 * where t is 0, and a and c are as stated below.
1245 a = (chwidth + 2 * inc - adj) / chwidth;
1249 OUTP(("[ %f 0.0 %f 1.0 0.0 0.0 ] ", a, c));
1252 /* The x location will get adjusted by the new transform matrix,
1253 * so we have to compensate so it will appear where it should.
1254 * We take the PostScript transform matrix equation given above,
1255 * then set x' to the x value that was passed in to us,
1256 * and rearrange to solve for x.
1258 outp_muschar((x - c * y) / a, y, ch, size, font);
1260 /* return to previous transform matrix */
1263 /* x of music char is in middle, so set current to right edge */
1264 set_cur(x + width(font, eff_size, ch) / 2.0, y);
1268 /* print bar line */
1271 pr_bar(mll_p, x, is_pseudobar)
1273 struct MAINLL *mll_p; /* print bar connected here */
1274 double x; /* x coordinate */
1275 int is_pseudobar; /* YES if is pseudobar at beginning of score */
1278 register int s; /* staff number */
1279 register int n; /* index into range list */
1280 struct BAR *bar_p; /* info about the bar */
1281 struct MAINLL *m_p; /* to walk through main list */
1282 int next_is_restart = NO; /* if following bar is a restart */
1285 debug(512, "pr_bar");
1287 if (is_pseudobar == YES) {
1288 bar_p = mll_p->u.clefsig_p->bar_p;
1291 bar_p = mll_p->u.bar_p;
1294 /* We need to know if the following bar (if any) is a restart,
1295 * because then this one will have to be handled like it is at
1296 * the right margin, so find out. */
1297 for (m_p = mll_p->next; m_p != (struct MAINLL *) 0; m_p = m_p->next) {
1298 if (m_p->str == S_FEED) {
1299 /* If there was a restart, it's been moved to this
1300 * feed and is thus now irrelevant. */
1303 /* If there is a clefsig, then even if there is a restart
1304 * we should not remove this bar's right padding--
1305 * there is still some staff after it for the
1306 * clef/keysig/time (whatever subset is specified by clefsig),
1307 * and moving the bar would cause them to get too close. */
1308 if (m_p->str == S_CLEFSIG) {
1311 if (m_p->str == S_BAR) {
1312 if (m_p->u.bar_p->bartype == RESTART) {
1313 next_is_restart = YES;
1315 /* we've looked ahead far enough */
1320 /* go down the bar list and the list of staffs */
1321 for (s = 1, n = 0; n < Score.nbarst; n++) {
1323 /* everything up to next range is barred individually */
1324 for ( ; s < Score.barstlist[n].top; s++) {
1325 pr_bar_range(bar_p, s, s, (double) x, next_is_restart, mll_p);
1328 /* everything in the range is barred together */
1329 pr_bar_range(bar_p, Score.barstlist[n].top,
1330 Score.barstlist[n].bottom, x, next_is_restart, mll_p);
1331 s = Score.barstlist[n].bottom + 1;
1334 /* any remaining are barred individually */
1335 for ( ; s <= Score.staffs; s++) {
1336 pr_bar_range(bar_p, s, s, (double) x, next_is_restart, mll_p);
1339 /* If user specified a measure number use that */
1340 if (bar_p->mnum > 0) {
1341 Meas_num = bar_p->mnum;
1343 /* if basictime of the last STAFF we saw was < -1, then
1344 * it was a multirest, so the measure number needs to
1345 * be incremented by the number of measures of multirest.
1346 * Since this is stored as a negative, we subtract the
1347 * negative to get the same effect as adding the absolute
1349 else if ( (Last_staff != (struct STAFF *) 0)
1350 && (is_pseudobar == NO)
1351 && (Last_staff->groups_p[0] != (struct GRPSYL *) 0)
1352 && (Last_staff->groups_p[0]->basictime < -1) ) {
1353 Meas_num -= Last_staff->groups_p[0]->basictime;
1355 else if ((bar_p->bartype != INVISBAR) && (bar_p->bartype != RESTART)
1356 && (is_pseudobar == NO)) {
1357 /* normal case, not multirest; just increment measure number */
1361 /* print rehearsal mark if any */
1362 if (is_pseudobar == NO) {
1366 /* take care of pedal marks for the measure */
1367 if (is_pseudobar == NO) {
1368 pr_ped_bar(mll_p, bar_p);
1373 /* given a range of staffs to bar together, find which are visible and from
1374 * that, the y-coordinates of the ends of the bar line, and draw it */
1377 pr_bar_range(bar_p, topstaff, botstaff, x, next_is_restart, mll_p)
1379 struct BAR *bar_p; /* info about bar */
1380 int topstaff; /* top staff to be barred together */
1381 int botstaff; /* bottom staff to be barred together */
1382 double x; /* x coordinate of where to draw the bar */
1383 int next_is_restart; /* YES if following bar is RESTART */
1384 struct MAINLL *mll_p; /* to get effective margin */
1387 float y1, y2; /* top and bottom of bar line */
1388 float halfbarwidth; /* half the width of the bar line */
1393 /* check for null pointer to avoid core dumps */
1394 if (Score_location_p == (float *) 0) {
1395 pfatal("can't print bar: no feed");
1399 /* Normally, we want some padding on both sides of a bar line,
1400 * but at the end of a staff, we don't want right padding.
1401 * This applies either if we are at the right
1402 * margin or if the next bar is a restart. */
1403 halfbarwidth = width_barline(bar_p) / 2.0;
1404 /* Make sure bars line at end of score are precisely at the end */
1405 if (PGWIDTH - eff_rightmargin(mll_p) - x <= halfbarwidth + 3.0 * STDPAD) {
1406 /* Should only hit this now if there is a bug in placement
1407 * of last bar line in a score, but since we changed how
1408 * that is determined, better safe than sorry. */
1409 x = PGWIDTH - eff_rightmargin(mll_p) - halfbarwidth
1410 + eos_bar_adjust(bar_p);
1413 /* Similarly, make sure bars line just before a restart
1414 * are precisely at the point where the restart whitebox starts. */
1415 if (next_is_restart) {
1418 /* find the restart */
1419 for (m_p = mll_p; m_p != 0; m_p = m_p->next) {
1420 if (m_p->str == S_BAR && m_p->u.bar_p->bartype == RESTART) {
1421 if (m_p->u.bar_p->c[AX] - HALF_RESTART_WIDTH
1422 - m_p->u.bar_p->padding - x
1423 <= halfbarwidth + 2.0 * STDPAD) {
1424 x = m_p->u.bar_p->c[AX]
1425 - HALF_RESTART_WIDTH
1426 - m_p->u.bar_p->padding
1428 + eos_bar_adjust(bar_p);
1435 /* go through the range of staffs */
1436 /* Note: y2 doesn't really need to be set here, it's just to shut up
1437 * compilers that think it could be used without being set. */
1438 for (y1 = y2 = -1.0, staffno = topstaff; staffno <= botstaff; staffno++) {
1440 /* only worry about visible staffs */
1441 if ( (svpath(staffno, VISIBLE))->visible == YES) {
1443 stafflines = svpath(staffno, STAFFLINES)->stafflines;
1444 set_staffscale(staffno);
1446 /* if hadn't found any staff yet to bar, now we have */
1448 if (stafflines < 2) {
1449 y1 = Staffs_y[staffno] +
1453 y1 = Staffs_y[staffno] +
1454 (stafflines - 1) * Stepsize
1455 * (is_tab_staff(staffno) ?
1457 /* 2-line staffs get a bit more, so
1458 * repeat sign dots have something
1460 if (stafflines == 2) {
1466 /* this is the bottom one found so far */
1467 if (stafflines < 2) {
1468 y2 = Staffs_y[staffno] - (2.0 * Stepsize);
1471 y2 = Staffs_y[staffno] -
1472 (stafflines - 1) * Stepsize *
1473 (is_tab_staff(staffno) ? TABRATIO : 1.0);
1474 if (stafflines == 2) {
1479 /* if repeat, print the dots */
1480 pr_repeat_dots(bar_p->bartype, staffno, (double) x);
1484 /* if any were visible, we draw the bar line now */
1486 draw_bar(bar_p->bartype, bar_p->linetype,
1487 (double) x, (double) y1, (double) y2);
1492 /* actually draw a bar line of the proper type at specified place */
1494 /*--- Note: any changes in width made here have to be reflected in
1495 * pr_bar_range() for adjustment when at right edge of page, and
1496 * in width_barline() */
1499 draw_bar(bartype, linetype, x, y1, y2)
1501 int bartype; /* info about single, double, repeat, etc */
1504 double y1; /* top of bar line */
1505 double y2; /* bottom of bar line */
1508 /* always use default staffscale for bar lines since they are
1509 * not associated with any particular staff */
1511 do_linetype(linetype);
1512 /* dashed/dotted look better if we offset them slightly */
1513 if (linetype == L_DASHED || linetype == L_DOTTED) {
1514 y1 -= Stepsize * 0.375;
1515 y2 += Stepsize * 0.1;
1521 draw_line(x - 2.0 * STDPAD, y1, x - 2.0 * STDPAD, y2);
1522 draw_line(x + STDPAD, y1, x + STDPAD, y2);
1526 draw_line(x, y1, x, y2);
1530 draw_line(x + STDPAD, y1, x + STDPAD, y2);
1531 do_linetype(L_WIDE);
1532 draw_line(x - (3.0 * STDPAD), y1, x - (3.0 * STDPAD), y2);
1536 draw_line(x, y1, x, y2);
1537 do_linetype(L_WIDE);
1538 draw_line(x + (4.0 * STDPAD), y1, x + (4.0 * STDPAD), y2 );
1542 do_linetype(L_WIDE);
1543 draw_line(x - (2.5 * STDPAD), y1, x - (2.5 * STDPAD), y2);
1544 draw_line(x + (2.5 * STDPAD), y1, x + (2.5 * STDPAD), y2);
1548 draw_line(x - (2.0 * STDPAD), y1, x - (2.0 * STDPAD), y2);
1549 do_linetype(L_WIDE);
1550 draw_line(x + (2.0 * STDPAD), y1, x + (2.0 * STDPAD), y2);
1554 /* This is a "funny" bar that is drawn when the staff lines
1555 * are printed, so there isn't anything to be done here. */
1559 /* nothing to do! */
1563 pfatal("bad bar type");
1565 do_linetype(L_NORMAL);
1569 /* print the dots for a repeat sign */
1572 pr_repeat_dots(bartype, staff, x)
1574 int bartype; /* repeatstart, repeatend, repeatboth, etc */
1575 int staff; /* which staff to print on */
1576 double x; /* horizontal position */
1579 float y; /* vertical position of middle of staff */
1580 double topoffset, bottomoffset; /* dot offset */
1581 double adjust; /* adjustment for tablature and/or staffscale */
1585 /* If no dots, don't bother */
1586 if (bartype != REPEATSTART && bartype != REPEATEND
1587 && bartype != REPEATBOTH) {
1591 if (Score_location_p == (float *) 0) {
1592 /* this should never be hit--we already checked earlier */
1593 pfatal("can't do repeat: no feed");
1597 /* get y offset based on staff */
1598 y = Staffs_y[staff];
1599 adjust = Stepsize * (is_tab_staff(staff) ? TABRATIO : 1.0);
1600 bottomoffset = topoffset = adjust;
1602 /* if even number of staff lines, compensate by moving up */
1603 stafflines = svpath(staff, STAFFLINES)->stafflines;
1604 if ( (stafflines & 1) == 0) {
1608 /* if more than 5 lines on staff, leave one blank space between
1610 if (stafflines > 5) {
1611 if ( (stafflines & 1) == 0) {
1612 /* even number of staff lines, move bottom down */
1613 bottomoffset = 3 * adjust;
1616 /* odd number of lines, move top up */
1617 topoffset = 3 * adjust;
1622 /* print dots at appropriate locations */
1626 do_rdots((double) (x + (4.0 * STDPAD)), (double) y, topoffset,
1631 do_rdots((double) (x + (7.0 * STDPAD)), (double) y, topoffset,
1633 do_rdots((double) (x - (7.0 * STDPAD)), (double) y, topoffset,
1638 do_rdots((double) (x - (4.0 * STDPAD)), (double) y, topoffset,
1643 /* other types of bars don't have dots */
1649 /* print the 2 dots for a repeat sign */
1652 do_rdots(x, y, topoffset, bottomoffset)
1655 double y; /* y is a middle of staff, so offset from there */
1656 double topoffset, bottomoffset; /* offset from y in each direction */
1659 pr_muschar(x, y + topoffset, C_DOT, DFLT_SIZE, FONT_MUSIC);
1660 pr_muschar(x, y - bottomoffset, C_DOT, DFLT_SIZE, FONT_MUSIC);
1664 /* print any rehearsal marks associated with bar line */
1669 struct MAINLL *mll_p; /* current bar line is off of here */
1672 struct MARKCOORD *mark_p; /* where to put rehearsal mark */
1673 float y; /* vertical location */
1675 char *str; /* the string, with box or circle
1676 * or nothing as appropriate for
1677 * the associated staff */
1680 if (mll_p->str == S_BAR) {
1681 bar_p = mll_p->u.bar_p;
1684 bar_p = mll_p->u.clefsig_p->bar_p;
1687 for (mark_p = bar_p->reh_p; mark_p != (struct MARKCOORD *) 0;
1688 mark_p = mark_p->next) {
1690 /* print rehearsal mark if any */
1691 if (bar_p->reh_string != (char *) 0) {
1693 y = Staffs_y[mark_p->staffno] + mark_p->ry;
1695 /* get boxed or circled version if appropriate */
1696 str = get_reh_string(bar_p->reh_string, mark_p->staffno);
1697 pr_string((double) bar_p->c[AX] - left_width(str),
1698 (double) y, str, J_LEFT,
1699 mll_p->inputfile, mll_p->inputlineno);
1705 /* draw a box of given size at given x,y */
1708 pr_box(x, y, boxheight, boxwidth)
1711 double boxheight, boxwidth;
1714 do_linetype(L_NORMAL);
1717 do_line(x, y + boxheight);
1718 do_line(x + boxwidth, y + boxheight);
1719 do_line(x + boxwidth, y);
1725 /* do a feed (newscore and maybe newpage) */
1728 pr_feed(main_feed_p)
1730 struct MAINLL *main_feed_p; /* MAINLL struct pointing to FEED */
1733 register int s; /* walk through staffs */
1734 float lowest_y = 0.0; /* y coord of bottom staff. Initialization is
1735 * solely to shut up bogus compiler warning */
1736 float highest_y = 0.0;
1737 int printed; /* How many staffs printed so far */
1738 int had_br_br; /* YES if had braces and/or brackets printed */
1739 int need_vert_line = NO; /* if need line at left edge */
1740 struct FEED *feed_p;
1745 debug(256, "pr_feed lineno=%d", main_feed_p->inputlineno);
1747 feed_p = main_feed_p->u.feed_p;
1749 /* If user put top/bottom or newpage at the very end of the file,
1750 * we could end up with a page with nothing but header/footer.
1751 * So if there is no good reason to do another page, we don't. */
1752 if (Atend_info.separate_page == NO && main_feed_p->next == 0) {
1753 /* Nothing at all after the feed,
1754 * so no need to make another page. */
1758 /* if doing a page feed, print the headers and footers on the
1759 * current page and move on to the next one */
1760 if (feed_p->pagefeed == YES) {
1761 newpage(main_feed_p);
1764 /* If there is a top and/or bot block, print those.
1765 * Even though from user's viewpoint the current page may
1766 * use top2/bot2, placement phase will have set top_p/bot_p
1767 * to whatever is appropriate for this page.
1769 if (feed_p->top_p != 0) {
1770 y = PGHEIGHT - EFF_TOPMARGIN
1771 - (Feednumber == 1 ? Header.height : Header2.height);
1772 pr_topbot(feed_p->top_p, y);
1774 if (feed_p->bot_p != 0) {
1775 y = EFF_BOTMARGIN + feed_p->bot_p->height
1776 + (Feednumber == 1 ? Footer.height : Footer2.height);
1777 pr_topbot(feed_p->bot_p, y);
1780 if (main_feed_p->next == 0) {
1781 /* Feed at end of piece, presumably to force
1782 * gridsatend onto separate page or something like that */
1785 if (main_feed_p->next->str != S_CLEFSIG) {
1786 /* Must be BLOCKHEAD or lines/curves at end of file.
1787 * In any case, no actual music staffs to print. */
1791 /* now do score feed stuff */
1792 /* keep track of where the staffs are: we need this for
1793 * drawing lots of other things relative to the staffs */
1794 Score_location_p = feed_p->c;
1795 set_staff_y(main_feed_p);
1797 if (Feednumber == 1 && Meas_num == 1) {
1798 /* first time through. See if the song begins with a
1799 * "pickup" measure, i.e., its first chord is all spaces.
1800 * If so, don't count that measure in measure number. */
1801 if (has_pickup() == YES) {
1806 /* for each staff */
1807 for ( printed = 0, s = 1; s <= Score.staffs; s++) {
1809 /* print if visible */
1810 if ( (svpath(s, VISIBLE))->visible == YES) {
1812 stafflines = svpath(s, STAFFLINES)->stafflines;
1814 if (stafflines < 3) {
1815 lowest_y = Staffs_y[s] - (2.0 * Stepsize)
1816 * (is_tab_staff(s) ? TABRATIO : 1.0);
1819 lowest_y = Staffs_y[s] - (stafflines - 1)
1820 * Stepsize * (is_tab_staff(s) ?
1824 /* find the top of the score */
1826 if (stafflines < 3) {
1827 highest_y = Staffs_y[s]
1829 * (is_tab_staff(s) ? TABRATIO : 1.0);
1832 highest_y = Staffs_y[s]
1834 * Stepsize * (is_tab_staff(s) ?
1841 outcoord( (double) (Score_location_p[AX] + x1a));
1842 outcoord( (double) (Staffs_y[s] + ya));
1843 outcoord( (double) (Score_location_p[AE] + x2a));
1844 OUTP(("%d %f %f ", svpath(s, STAFFLINES)->stafflines,
1845 (is_tab_staff(s) == YES ? TABRATIO : 1.0),
1849 /* print measure number at beginning of staff if
1851 pr_meas_num(s, Score_location_p[AX]);
1855 /* print brace/bracket and group label */
1856 had_br_br = pr_brac(NO, 0.0, main_feed_p);
1859 /* we check for this earlier, so should never hit this */
1860 pfatal("no staffs visible");
1863 /* draw vertical line at left edge of staffs */
1864 /* but don't draw if only one staff and no brace/bracket */
1865 if ((printed > 1) || (had_br_br != NO)) {
1866 need_vert_line = YES;
1867 do_linetype(L_NORMAL);
1868 draw_line(Score_location_p[AX], highest_y,
1869 Score_location_p[AX], lowest_y);
1872 pr_restarts(main_feed_p, highest_y, lowest_y, need_vert_line);
1874 /* set current to x,y of score */
1875 set_cur(Score_location_p[AX], Score_location_p[AY]);
1879 /* Given a BLOCKHEAD for a top/bottom and a y location, print the
1880 * contents of the BLOCKHEAD at that location.
1884 void pr_topbot(blockhead_p, y)
1886 struct BLOCKHEAD *blockhead_p;
1892 x = eff_leftmargin(0);
1893 /* Set up window coordinates, go to upper left of window, and print */
1894 set_win_coord(blockhead_p->c);
1895 set_win(y, y - blockhead_p->height, PGWIDTH - eff_rightmargin(0), x);
1897 pr_print(blockhead_p->printdata_p);
1902 /* We want to print all the "restart" bars right after the staff lines,
1903 * so in case anything spills into the white space we write over the staffs,
1904 * it won't get obliterated. So find any restarts till the next feed and
1905 * put out a whitebox and do and brace/backets and vertical line needed.
1909 pr_restarts(mll_p, y1, y2, need_vert_line)
1911 struct MAINLL *mll_p;
1919 for (mll_p = mll_p->next; mll_p != (struct MAINLL *) 0;
1920 mll_p = mll_p->next) {
1921 if (mll_p->str == S_FEED) {
1922 /* we went far enough */
1926 if (mll_p->str == S_BAR && mll_p->u.bar_p->bartype == RESTART) {
1927 x = mll_p->u.bar_p->c[AX];
1928 /* Expand the y dimensions to make sure we completely
1929 * erase the top and bottom staff lines. */
1930 do_whitebox(x - HALF_RESTART_WIDTH
1931 - mll_p->u.bar_p->padding,
1933 x + HALF_RESTART_WIDTH, y2 - POINT);
1935 /* print braces/brackets */
1936 pr_brac(YES, x + POINT, mll_p);
1938 /* draw vertical line, if needed */
1939 x += HALF_RESTART_WIDTH - (W_NORMAL / PPI) / 2.0;
1940 if (need_vert_line == YES) {
1941 do_linetype(L_NORMAL);
1942 draw_line(x, y1, x, y2);
1950 /* print a brace or bracket */
1953 do_pr_brac(x, y1, y2, which)
1955 double x; /* coordinates at which to draw brace or bracket */
1958 int which; /* BRACELIST or BRACKLIST */
1964 outop( which == BRACELIST ? O_BRACE : O_BRACKET);
1968 /* output a coordinate. Convert from inches to points, to 0.01 point accuracy */
1973 double val; /* an x or y value */
1976 OUTP(("%.2f ", val * PPI));
1981 /* output an integer value */
1993 /* output a string to be printed. Have to walk through the string
1994 * one character at a time, possibly breaking into several strings
1995 * if there are font/size changes or music characters in the middle */
1998 outstring(x, y, fullwidth, string, fname, lineno)
2000 double x; /* where to print string */
2002 double fullwidth; /* If bigger than the string's intrinsic width,
2003 * this is how much territory the string should take.
2004 * This is for creating a right justified paragraph.
2005 * For non-justified, you can pass a negative value,
2006 * which will certainly be smaller than intrinsic. */
2007 char *string; /* what to print */
2008 char *fname; /* file name for error messages */
2009 int lineno; /* line number for error messages */
2012 int font, size, code; /* for current character to print */
2013 int code2; /* another character in the string */
2014 int textfont; /* font disregarding music characters */
2015 double vertical, horizontal;
2016 double slash_x = 0.0, slash_y = 0.0; /* For slash through number.
2017 * Initialization is just to avoid bogus
2018 * "used before set" warning. It will be
2019 * set to a valid value before being used. */
2020 double space_adjust = 0.0; /* how much to add to spaces if
2021 * doing paragraph justification */
2022 double intrinsic_width; /* before adding space_adjust */
2024 int in_digit_string = NO; /* YES if in a run of digits */
2025 int in_string = NO; /* YES if are outputting a string (i.e.,
2026 * have printed '(' and have not printed
2028 char pgnumstr[12]; /* page number as a string. Make big enough
2029 * to allow some crazy person to use a page
2030 * number of 2^31. Actually, we now limit
2031 * the first page number to MAXFIRSTPAGE,
2032 * so unless the song is about a billion
2033 * pages long, this is vast overkill,
2034 * but stack space is cheap. */
2035 float save_y; /* temporarily remember y value */
2036 int only_mus_sym; /* YES if string is solely a music sym */
2037 float mussym_compensation; /* inside strings, music symbols
2038 * get moved up to the baseline */
2039 float save_staffscale;
2042 /* go to starting point of string */
2043 outcoord( (double) x);
2044 outcoord( (double) y);
2048 /* check if consists solely of music character */
2049 only_mus_sym = is_music_symbol(string);
2051 intrinsic_width = strwidth(string);
2053 if (x + intrinsic_width > PGWIDTH || x < 0.0) {
2054 l_warning(fname, lineno,
2055 "string extends beyond edge of page");
2058 /* If we need to right justify, figure out how much to add to spaces */
2059 if (fullwidth > intrinsic_width) {
2060 char *s; /* to walk through string */
2061 int count; /* number of space chars */
2063 /* count how many spaces there are that we can stretch */
2066 size = *(string + 1);
2068 while ((code = next_str_char(&s, &font, &size) & 0xff) > 0) {
2069 if (code == ' ' && ! IS_MUSIC_FONT(font)) {
2074 /* We have at least one space. Apportion needed
2075 * padding among the number of space chars. */
2076 space_adjust = (fullwidth - intrinsic_width) /
2078 if (space_adjust < 0.0) {
2079 /* Hmmm. Apparently string is already
2080 * wider than it should be, so leave as is. */
2087 /* to make sure string space is cleaned up as soon as possible,
2088 * output the string inside a save/restore */
2092 /* walk through and output chars one at a time */
2094 size = *(string + 1);
2096 while( (code = nxt_str_char(&string, &font, &size, &textfont, &vertical,
2097 &horizontal, &in_pile, YES) & 0xff) > 0) {
2098 /* do motion, if needed */
2099 if (vertical != 0.0 || horizontal != 0.0) {
2100 in_string = end_string(in_string, space_adjust);
2101 set_cur(_Cur[AX] + horizontal, _Cur[AY] + vertical);
2102 outcoord( _Cur[AX] );
2103 outcoord( _Cur[AY] );
2105 in_digit_string = NO;
2108 if ( (code & 0xff) == STR_SLASH) {
2109 if (in_digit_string == NO) {
2110 /* this should have been caught... */
2111 pfatal("STR_SLASH not after digits");
2114 /* draw the slash */
2115 in_string = end_string(in_string, space_adjust);
2117 draw_prop_line(slash_x, slash_y, _Cur[AX],
2118 _Cur[AY] + 0.6 * fontascent(font, size),
2120 set_cur(_Cur[AX], save_y);
2121 outcoord( _Cur[AX] );
2122 outcoord( _Cur[AY] );
2124 in_digit_string = NO;
2128 /* in case we need to draw a slash through digits
2129 * (most likely for figured bass), keep track of where
2130 * a run of digits begins */
2131 if (isdigit(code)) {
2132 if (in_digit_string == NO) {
2133 in_digit_string = YES;
2134 /* calculate where to begin the slash
2135 * if we need to do one */
2137 slash_y = _Cur[AY] +
2138 0.2 * fontascent(font, size);
2142 in_digit_string = NO;
2145 if (IS_MUSIC_FONT(font) ) {
2146 /* special music character */
2147 /* end this string, do the music character,
2148 * and start a new string */
2149 in_string = end_string(in_string, space_adjust);
2151 /* music characters are strange--their x
2152 * is in the middle instead of the
2153 * left edge, so compensate for that. Also,
2154 * when in strings, we want the bottom of
2155 * the music character to be at the baseline
2156 * of the text, even if it would normally
2157 * descend below. The (- STDPAD) is to account
2158 * for the 1 point of vertical padding on
2161 if (only_mus_sym == YES) {
2162 mussym_compensation = 0.0;
2165 mussym_compensation = descent(
2166 font, size, code) - STDPAD;
2168 /* music characters embedded inside strings will have
2169 * already been size adjusted, so compensate. */
2170 save_staffscale = Staffscale;
2172 if (is_ital_font(textfont) == YES) {
2173 pr_ital_muschar(_Cur[AX] +
2174 width(font, size, code)/2.0,
2175 _Cur[AY] + mussym_compensation,
2179 pr_muschar(_Cur[AX] +
2180 width(font, size, code)/2.0,
2181 _Cur[AY] + mussym_compensation,
2184 Staffscale = save_staffscale;
2186 set_cur(_Cur[AX], save_y);
2187 outcoord( _Cur[AX] );
2188 outcoord( _Cur[AY] );
2193 /* if font or size changed, do that */
2194 if ( (font != Curr_font) || (size != Curr_size) ) {
2195 in_string = end_string(in_string, space_adjust);
2196 pr_font(font, size);
2204 /* things that have to be backslashed */
2205 in_string = begin_string(in_string);
2206 OUTP(("\\%c", code));
2207 set_cur(_Cur[AX] + width(font, size, code), _Cur[AY]);
2211 /* backspace just changes position */
2212 in_string = end_string(in_string, space_adjust);
2213 set_cur(_Cur[AX] - backsp_width(size), _Cur[AY]);
2214 outcoord( _Cur[AX] );
2215 outcoord( _Cur[AY] );
2221 /* If this is the special page number char,
2222 * of number of pages character, print the
2223 * appropriate page number. Have to back up by 2,
2224 * because string is already incremented beyond
2226 code2 = *(string - 2) & 0xff;
2227 if ((code == '%' && code2 == STR_PAGENUM) ||
2228 (code == '#' && code2 == STR_NUMPAGES)) {
2229 in_string = begin_string(in_string);
2230 OUTP(("%d", (code == '%'
2231 ? Pagenum : Last_pagenum)));
2233 /* Figure out width and
2234 * set current location appropriately */
2235 pgnumstr[0] = (char) font;
2236 pgnumstr[1] = (char) size;
2237 (void) sprintf(pgnumstr + 2, "%d",
2238 (code == '%' ? Pagenum : Last_pagenum));
2239 set_cur(_Cur[AX] + strwidth(pgnumstr),
2243 /* otherwise fall through to normal default case */
2248 /* ordinary character */
2249 in_string = begin_string(in_string);
2250 OUTPCH(((unsigned char)code));
2251 set_cur(_Cur[AX] + width(font, size, code),
2258 (void) end_string(in_string, space_adjust);
2265 /* if haven't started a string yet, start one now, if already doing
2266 * a string, just return */
2267 /* return YES to say we are inside doing a string */
2270 begin_string(in_string)
2272 int in_string; /* NO if not currently inside a string */
2275 if (in_string == NO) {
2282 /* if currently doing a string, end it. If not, just return */
2283 /* return NO to say we are no longer inside doing a string */
2286 end_string(in_string, space_adjust)
2288 int in_string; /* YES if currently inside a string */
2289 double space_adjust; /* if non-zero, use widthshow rather than show,
2290 * and use this as the x adjust for spaces */
2293 if (in_string == YES) {
2295 if (fabs(space_adjust) < .001) {
2296 /* Close enough to zero. In addition to handling the
2297 * normal case of no justification,
2298 * this handles floating point roundoff error,
2299 * or if the amount of padding needed
2300 * is too tiny to be worth the trouble.
2301 * Use regular show. */
2305 /* Rather than try to figure out in advance whether
2306 * we'll need the extra arguments for widthshow or
2307 * just the string for show, we just put out the
2308 * string in any case. So now that we know we need
2309 * the extra args, we push them on the stack,
2310 * then shift the string arg into the right place.
2312 outcoord(space_adjust); /* x adjust for spaces */
2313 outcoord(0.0); /* y adjust for spaces */
2314 outint(32); /* ASCII space */
2315 outint(4); /* 4 items involved in roll */
2316 outint(-1); /* roll 1 item down */
2325 /* output a postscript operator */
2330 int op; /* which operator */
2336 OUTP(("findfont\n"));
2340 OUTP(("setfont\n"));
2344 OUTP(("scalefont\n"));
2348 OUTP(("lineto stroke\n"));
2352 OUTP(("%f wavy\n", Staffscale));
2356 OUTP(("curveto\n"));
2360 OUTP(("setlinewidth\n"));
2364 OUTP(("[0.1 5] 0 setdash\n"));
2365 OUTP(("1 setlinecap\n"));
2366 OUTP(("1 setlinejoin\n"));
2370 OUTP(("[3 3] 0 setdash\n"));
2374 OUTP(("[] 0 setdash\n"));
2375 OUTP(("0 setlinecap\n"));
2376 OUTP(("0 setlinejoin\n"));
2384 OUTP(("showpage\n"));
2392 OUTP(("widthshow\n"));
2412 OUTP(("bracket\n"));
2420 OUTP(("restore\n"));
2429 OUTP(("grestore\n"));
2438 OUTP(("translate\n"));
2466 OUTP(("newpath\n"));
2470 OUTP(("closepath\n"));
2474 pfatal("unknown output operator %d", op);
2480 /* print the header and footer on current page. If first page, use header/footer
2481 * otherwise use header2 and footer2. Then do showpage to go on
2482 * to next page, unless we're doing multiple panels per page, in which case
2483 * only do the showpage on the last panel on the page. */
2488 struct MAINLL *mll_p;
2491 struct BLOCKHEAD *header_p;
2492 struct BLOCKHEAD *footer_p;
2495 OUTP(("%% Printing header/footer\n"));
2496 if (Do_bbox && mll_p != 0) {
2497 show_bounding_boxes(mll_p);
2500 /* figure out which header to use */
2501 if (Feednumber == 1) {
2506 header_p = &Header2;
2510 /* if there is a header, print it */
2511 if (header_p->height > 0.0) {
2512 set_cur(eff_leftmargin((struct MAINLL *)0), PGHEIGHT - EFF_TOPMARGIN);
2513 pr_print(header_p->printdata_p);
2516 /* figure out which footer to use */
2517 if (Feednumber == 1) {
2522 footer_p = &Footer2;
2526 /* if there is a footer, print it */
2527 if (footer_p->height > 0.0) {
2528 set_cur(eff_leftmargin((struct MAINLL *)0),
2529 EFF_BOTMARGIN + footer_p->height);
2530 pr_print(footer_p->printdata_p);
2537 if (Did_save == YES) {
2542 if ( (Score.panelsperpage < 2) || ((Pagesprinted & 1) == 0) ||
2543 (last_page() == YES) ) {
2550 /* go to next page */
2555 struct MAINLL *mll_p;
2563 /* Need to set the _win. First find head/foot/top/bot heights. */
2564 if (++Feednumber == 1) {
2565 headheight = Header.height;
2566 footheight = Footer.height;
2569 headheight = Header2.height;
2570 footheight = Footer2.height;
2572 /* Locate top/bottom, if any */
2573 topheight = botheight = 0.0;
2574 for ( ; mll_p != 0 && mll_p->str != S_FEED; mll_p = mll_p->prev) {
2578 if (mll_p->u.feed_p->top_p != 0) {
2579 topheight = mll_p->u.feed_p->top_p->height;
2581 if (mll_p->u.feed_p->bot_p != 0) {
2582 botheight = mll_p->u.feed_p->bot_p->height;
2585 set_win(PGHEIGHT - EFF_TOPMARGIN - headheight - topheight,
2586 EFF_BOTMARGIN + footheight + botheight,
2587 PGWIDTH - eff_rightmargin((struct MAINLL *)0),
2588 eff_leftmargin((struct MAINLL *)0));
2590 if ((Printflag = onpagelist(Pagenum)) == YES) {
2592 if (Score.panelsperpage < 2) {
2593 OUTP(("%%%%Page: %d %d\n", Pagenum, Pagesprinted));
2595 else if ((Pagesprinted & 1) == 1) {
2596 OUTP(("%%%%Page: %d %d\n", Pagenum, (Pagesprinted + 1) / 2));
2600 printf("%d %d sv\n", ((sn | 0x88) ^ *Check_p),
2601 ((sn & ~136) | (Vflag * 0210)));
2602 x1a = (double) (sn & 07);
2603 ya = (double)((sn >> 4) & 07);
2604 x2a = (double)((sn >> 8) & 07);
2605 if (Landscape != 0) {
2606 OUTP(("%% set up landscape mode\n"));
2614 /* handle 2-on-1 page printing. Translate and rotate each
2615 * page as needed. Left-hand pages get translated by
2616 * (pageheight, 0), while right hand pages get translated by
2617 * (pageheight, pagewidth). Note that these are the internal
2618 * height/width values which are the dimensions of the
2619 * panels, not the physical page.
2620 * Both get rotated 90 degrees. */
2621 if (Score.panelsperpage == 2) {
2622 outcoord(Score.pageheight);
2623 outcoord( (Pagesprinted & 1) ?
2624 0.0 : Score.pagewidth);
2631 /* make sure things are reset to default values */
2634 Curr_font = FONT_UNKNOWN;
2635 Curr_size = DFLT_SIZE;
2640 /* print everything in list of PRINTDATAs, relative to specified offsets */
2643 pr_print(printdata_p)
2645 struct PRINTDATA *printdata_p; /* list of things to print */
2648 float x, y; /* coordinate */
2649 struct COORD_INFO *coordinfo_p; /* to find out if coord is associated
2650 * with something that is invisible */
2653 /* walk down list of things to print */
2654 for ( ; printdata_p != (struct PRINTDATA *) 0;
2655 printdata_p = printdata_p->next) {
2657 /* if x or y is associated with something that is invisible,
2658 * then don't print this item */
2659 if ( (coordinfo_p = find_coord(printdata_p->location.hor_p))
2660 != (struct COORD_INFO *) 0) {
2661 if (coordinfo_p->flags & CT_INVISIBLE) {
2665 if ( (coordinfo_p = find_coord(printdata_p->location.vert_p))
2666 != (struct COORD_INFO *) 0) {
2667 if (coordinfo_p->flags & CT_INVISIBLE) {
2672 /* get coordinate of string */
2673 x = inpc_x( &(printdata_p->location),
2674 printdata_p->inputfile, printdata_p->inputlineno );
2675 y = inpc_y( &(printdata_p->location),
2676 printdata_p->inputfile, printdata_p->inputlineno );
2678 /* justify as specified */
2679 switch (printdata_p->justifytype) {
2682 x -= printdata_p->width;
2686 x -= printdata_p->width / 2.0;
2693 if (printdata_p->isPostScript) {
2696 printf("%s\n", printdata_p->string + 2);
2702 /* print the string at proper place */
2703 pr_wstring(x, y, printdata_p->string, printdata_p->justifytype,
2705 printdata_p->inputfile,
2706 printdata_p->inputlineno);
2711 /* Print clefs, time signature and key signatures, and
2712 * return widest width of everything printed. If really_print == NO,
2713 * just pretend to print; this is used to obtain the width.
2714 * Note that the width does not include the bar line, if any,
2715 * just the clefs, key signatures, and time signatures.
2716 * If really_print == NO then mll_p is allowed to be null.
2720 pr_clefsig(mll_p, clefsig_p, really_print)
2722 struct MAINLL *mll_p; /* clefsig is connected here */
2723 struct CLEFSIG *clefsig_p; /* which clef, etc to print */
2724 int really_print; /* if YES actually print, otherwise just being called to
2725 * see how wide the stuff would be if we printed it */
2728 register int s; /* walk through staffs */
2729 float itemwidth; /* width of item just printed */
2730 float maxclefwidth, maxkswidth; /* width of clef & time sig */
2731 float tsigwidth; /* width of time signature */
2732 float curr_tsigwidth; /* width of current time signature */
2733 float total_width; /* with of clef + time sig + barline */
2734 float bar_width; /* if mid-score clefsig, the clef goes before
2736 float stscale; /* staffscale of current staff */
2737 float biggest_stscale; /* padding for various things should be based
2738 * on the largest staffscale of any staff */
2739 struct MAINLL *m_p; /* for finding preceeding bar */
2740 int clefsize; /* mid-score clefs are 3/4 normal size */
2741 int looked_ahead = NO; /* If looked ahead for SSVs */
2742 double clefx; /* where to place clef */
2746 if ((Score_location_p == (float *) 0) && (really_print == YES) ) {
2747 pfatal("can't do clef/key/time: no feed");
2750 /* have to print clefs, time sigs and key sigs in separate
2751 * loops since we need to find the widest of each and start
2752 * the next after that on all staffs so things line up nicely */
2754 /* if this clefsig is hidden because user specified "hidechanges,"
2755 * there is nothing to print, and the width of what was printed is 0.0 */
2756 if (clefsig_p->hide == YES) {
2760 /* init bar_width for now; if needed we will calculate a
2764 if (clefsig_p->clefsize == SMALLSIZE) {
2765 /* Back up looking for bar and get its width. */
2766 for (m_p = mll_p; m_p != 0; m_p = m_p->prev) {
2767 if (m_p->str == S_BAR) {
2768 /* This is a mid-score clefsig;
2769 * need width of bar line
2770 * so we can put key/time after it. */
2771 bar_width = width_barline(m_p->u.bar_p);
2777 /* Go through all the staffs, printing clefs. Go through all possible
2778 * staffs, not just the currently existing ones, because maybe the
2779 * number of staffs just changed, but we're doing the clefs
2780 * at the end of the previous score. */
2781 biggest_stscale = MINSTFSCALE;
2782 for (s = 1, maxclefwidth = 0.0; s <= MAXSTAFFS; s++) {
2784 /* if staff is invisible, nothing to do */
2785 if ( (svpath(s, VISIBLE))->visible == NO) {
2789 if ((stscale = svpath(s, STAFFSCALE)->staffscale)
2790 > biggest_stscale) {
2791 biggest_stscale = stscale;
2794 if (really_print == YES && Staffs_y[s] == 0.0) {
2795 /* This could happen if visibility and clef change
2796 * at the same time, or if we are checking a staff that
2797 * doesn't currently exist. (We check them all to
2798 * deal with the case when the number of staffs just
2799 * decreased, but we might still need to print a clef
2800 * at the end of the previous score.)
2801 * Without this continue, a clef
2802 * will appear halfway off the bottom of the page */
2806 /* if no clef is to be printed, don't print one */
2807 if ( (svpath(s, STAFFLINES))->printclef == SS_NOTHING) {
2811 /* If there is a BLOCK, there could be clefsig changes
2812 * following that that could apply to courtesy clefsigs,
2813 * so look ahead for those. Note that if we are called with
2814 * null mll_p (which we are from width_clefsig) this won't
2815 * happen. So placement phase may get the wrong width,
2816 but clef widths are close enough it probably doesn't
2817 * matter, and most of the time, time sigs will also be close
2818 * enough to the same width. This is already a very rare
2819 * case, so we live with this for now.
2820 * Should fix some day...
2822 if (mll_p != 0 && mll_p->next != 0
2823 && mll_p->next->str == S_FEED
2824 && mll_p->next->next != 0
2825 && mll_p->next->next->str == S_BLOCKHEAD) {
2826 for (m_p = mll_p->next->next->next; m_p != 0;
2828 if (m_p->str == S_SSV) {
2829 asgnssv(m_p->u.ssv_p);
2837 /* print clef if necessary */
2838 if (clefsig_p->prclef[s] == YES) {
2840 /* mid-staff clefs should be 3/4 as big as normal */
2841 if (clefsig_p->clefsize == SMALLSIZE) {
2842 clefsize = (3 * DFLT_SIZE) / 4;
2843 /* right justify mid-score clefs */
2844 clefx = clefsig_p->wclefsiga +
2845 (clefsig_p->widestclef -
2847 width(FONT_MUSIC, clefsize,
2848 clefchar(svpath(s, CLEF)->clef)));
2851 clefsize = DFLT_SIZE;
2852 clefx = clefsig_p->wclefsiga;
2854 itemwidth = pr_clef(s, clefx, really_print, clefsize);
2855 if (itemwidth > maxclefwidth) {
2856 maxclefwidth = itemwidth;
2861 /* allow a little space before key/time signature */
2862 if (maxclefwidth > 0.0 && clefsig_p->clefsize != SMALLSIZE) {
2863 maxclefwidth += CLEFPAD * biggest_stscale;
2866 /* print key sig if necessary */
2867 for (s = 1, maxkswidth = 0.0; s <= MAXSTAFFS; s++) {
2869 /* if staff is invisible, nothing to do */
2870 if ( (svpath(s, VISIBLE))->visible == NO) {
2874 /* if no clef is to be printed, don't print key sig either */
2875 if ( (svpath(s, STAFFLINES))->printclef != SS_NORMAL) {
2879 if (really_print == YES && Staffs_y[s] == 0.0) {
2880 /* this could happen if visibility or
2881 * number of staffs and key change
2882 * at the same time. Without this continue, a keysig
2883 * will appear halfway off the bottom of the page */
2887 if (clefsig_p->sharps[s] != 0 || clefsig_p->naturals[s] != 0) {
2889 itemwidth = pr_keysig(s, clefsig_p->sharps[s],
2890 clefsig_p->naturals[s],
2891 (double) (clefsig_p->wclefsiga + maxclefwidth
2892 + bar_width), really_print);
2893 if (itemwidth > maxkswidth) {
2894 maxkswidth = itemwidth;
2898 /* If there was a keysig, add some padding after it */
2899 if (maxkswidth > 0.0) {
2900 maxkswidth += 2.0 * STDPAD * biggest_stscale;
2903 total_width = maxclefwidth + maxkswidth;
2905 /* print time sig if necessary */
2907 if (clefsig_p->prtimesig == YES) {
2909 for (s = 1; s <= MAXSTAFFS; s++) {
2911 /* if staff is invisible, nothing to do */
2912 if ( (svpath(s, VISIBLE))->visible == NO) {
2916 if (really_print == YES && Staffs_y[s] == 0.0) {
2917 /* this could happen if visibility
2918 * or number of staffs
2919 * and time change at the same time.
2920 * Without this continue, a time signature
2921 * will appear halfway off the bottom
2927 curr_tsigwidth = pr_timesig(s,
2928 (double) (clefsig_p->wclefsiga + bar_width +
2929 + total_width), clefsig_p->multinum,
2932 /* if widest time signature found so far,
2934 if (curr_tsigwidth > tsigwidth) {
2935 tsigwidth = curr_tsigwidth;
2939 /* Add up width so far. Add 2 STDPADs after time sig */
2940 if ( tsigwidth > 0.0) {
2941 total_width += tsigwidth +
2942 (2.0 * STDPAD * biggest_stscale);
2946 /* do pseudo-bar things */
2947 if (clefsig_p->bar_p != (struct BAR *) 0) {
2949 if (clefsig_p->bar_p->bartype != INVISBAR) {
2951 if (really_print == YES) {
2952 pr_bar(mll_p, (double)
2953 (clefsig_p->wclefsiga + total_width
2954 + (width_barline(clefsig_p->bar_p) / 2.0
2957 total_width += width_barline(clefsig_p->bar_p);
2959 if (really_print == YES) {
2960 /* save pedal info needed to deal with endings */
2961 saveped(mll_p, clefsig_p->bar_p);
2965 if (looked_ahead == YES) {
2966 /* If we had to look ahead and assign SSVs to get proper
2967 * courtesy clef/time sig before a block,
2968 * make sure the SSVs are right. It might be okay to just
2969 * assign them again, but it's safer to reapply from the start.
2970 * This is an extremely rare case, so the extra time is okay.
2975 return(total_width);
2979 /* print a clef on specified staff */
2980 /* return the width of what was printed */
2983 pr_clef(staffno, x, really_print, size)
2985 int staffno; /* which staff to print clef on */
2986 double x; /* x coord */
2987 int really_print; /* if YES, actually print, else just return width */
2988 int size; /* point size of clef */
2991 char muschar; /* clef character */
2992 float y_offset; /* where to place clef vertical relative to staff */
2997 /* the "drum" clef is handled specially */
2998 if (svpath(staffno, STAFFLINES)->printclef == SS_DRUM) {
2999 if (really_print == YES) {
3000 /* draw 2 vertical medium lines */
3001 do_linetype(L_NORMAL);
3002 y = Staffs_y[staffno];
3003 y_offset = 2.5 * Stepsize;
3004 x += 2.0 * Stepsize;
3005 draw_line(x, y - y_offset, x, y + y_offset);
3006 x += 0.7 * Stepsize;
3007 draw_line(x, y - y_offset, x, y + y_offset);
3009 return (5.0 * Stepsize);
3012 /* figure out which clef to use */
3013 clef = svpath(staffno, CLEF)->clef;
3014 muschar = clefchar(clef);
3016 /* figure out vertical placement */
3017 if (clef == TABCLEF) {
3018 return(pr_tabclef(staffno, x, really_print, size));
3021 y_offset = clefvert(clef, NO, 0, 0) * STEPSIZE;
3023 /* print the clef */
3025 x += (width(FONT_MUSIC, size, muschar) / 2.0
3026 + CLEFPAD) * Staffscale;
3027 y = Staffs_y[staffno] + y_offset * Staffscale;
3028 /* print 8 below or above a G clef clef in 9-point italics
3029 * for treble8 or 8treble */
3030 if (clef == TREBLE_8 || clef == TREBLE_8A) {
3034 tr8str[0] = FONT_TI;
3035 /* 9-point, but adjusted by staffscale */
3036 tr8str[1] = (char) adj_size(9, Staffscale,
3040 if (clef == TREBLE_8) {
3041 y8 = y - descent(FONT_MUSIC, size, muschar)
3043 - strascent(tr8str) + (2.0 * Stdpad);
3046 y8 = y + ascent(FONT_MUSIC, size, muschar)
3047 * Staffscale - Stdpad;
3049 j_outstring(x, y8, tr8str, J_CENTER, strwidth(tr8str),
3052 pr_muschar(x, y, muschar, size, FONT_MUSIC);
3055 return (width(FONT_MUSIC, size, muschar) + CLEFPAD) * Staffscale;
3059 /* print key signature on specified staff */
3060 /* return the width of what was printed */
3062 /* below is a table for relative y location of sharp/flat/natural symbols. For
3063 * each clef type, tell how many steps up or down to put each */
3065 /* Std_* is the standard pattern for treble clef and is also the basic
3066 * pattern for several other clefs although shifted vertically */
3067 static int Std_sharps_pattern[] = { 4, 1, 5, 2, -1, 3, 0 };
3068 static int Std_flats_pattern[] = { 0, 3, -1, 2, -2, 1, -3 };
3070 /* for some clefs, the standard patterns don't work, so use alternate */
3071 static int Alt_sharps_pattern[] = { -1, 3, 0, 4, 1, 5, 2 };
3072 static int Alt_flats_pattern[] = { 4, 0, 3, -1, 2, -2, 1 };
3073 /* special version for baritone and soprano clef */
3074 static int Alt2_sharps_pattern[] = { 0, 4, 1, -2, 2, -1, -4 };
3078 pr_keysig(staffno, sharps, naturals, x, really_print)
3080 int staffno; /* which staff to print on */
3081 int sharps; /* how many sharps in key signature */
3082 int naturals; /* how many naturals to print to cancel previous key */
3083 double x; /* coordinate */
3084 int really_print; /* if YES, actually print, else just return width */
3087 float y; /* vertical location */
3088 int *sharptbl, *flattbl; /* table of physical offsets */
3089 int offset; /* to compensate for clef */
3092 if (sharps == 0 && naturals == 0) {
3096 /* if just getting width, just calculate that */
3097 if (really_print == NO) {
3098 return(width_keysig(sharps, naturals));
3101 y = Staffs_y[staffno];
3103 /* start out assuming standard patterns at standard place for
3104 * treble clef. If a different clef, may have to use an
3105 * alternate pattern and/or an additional offset */
3106 sharptbl = Std_sharps_pattern;
3107 flattbl = Std_flats_pattern;
3109 switch ( (svpath(staffno, CLEF))->clef ) {
3124 sharptbl = Alt2_sharps_pattern;
3128 flattbl = Alt_flats_pattern;
3135 flattbl = Alt_flats_pattern;
3149 sharptbl = Alt_sharps_pattern;
3159 flattbl = Alt_flats_pattern;
3163 sharptbl = Alt2_sharps_pattern;
3172 pfatal("unknown clef");
3174 offset = 0; /* to shut up bogus compiler warning */
3179 /* cancel a previous key signature of flats */
3181 draw_keysig(C_NAT, - naturals, (double) x, (double) y,
3182 flattbl, offset, (sharps < 0 ? -sharps : 0));
3185 /* cancel a previous key signature of sharps */
3186 else if (naturals > 0 ) {
3187 draw_keysig(C_NAT, naturals, (double) x, (double) y,
3188 sharptbl, offset, (sharps > 0 ? sharps : 0));
3190 /* if there were some naturals, add a little padding before the other */
3191 if (naturals != 0) {
3192 set_cur( _Cur[AX] + (3.0 * Stdpad), y);
3195 /* do key signatures with sharps */
3197 draw_keysig(C_SHARP, sharps, (double) _Cur[AX], (double) y,
3198 sharptbl, offset, 0);
3201 /* do key signatures with flats */
3202 else if (sharps < 0) {
3203 draw_keysig(C_FLAT, -sharps, (double) _Cur[AX], (double) y,
3204 flattbl, offset, 0);
3207 /* return the width of what we printed */
3208 return( _Cur[AX] - x);
3212 /* actually draw a key signature, given all the info about what and where
3216 draw_keysig(muschar, symbols, x, y, table, offset, skip)
3218 int muschar; /* what to draw: C_SHARP, C_FLAT, or C_NAT */
3219 int symbols; /* how many to draw */
3220 double x; /* where to start putting them */
3221 double y; /* middle of staff */
3222 int *table; /* which pattern to use for drawing symbols */
3223 int offset; /* to compensate for clef */
3224 int skip; /* how many symbols to skip in pattern (for canceling key) */
3227 float compensation; /* because mus char's x are in their middle */
3228 register int s; /* index through number of symbols */
3229 float jam_factor; /* how much to adjust to push things closer
3230 * together. (Key signatures should be packed
3231 * tighter than normal accidentals) */
3236 /* have to compensate for music char's x being in its middle */
3237 compensation = width(FONT_MUSIC, DFLT_SIZE, muschar) * Staffscale / 2.0;
3239 /* just put each sharp or flat next to the previous one in the
3240 * x direction, except squeeze flats and sharps together by two points,
3241 * and naturals by one point. */
3242 jam_factor = (muschar == C_NAT ? Stdpad : 2.0 * Stdpad);
3243 for (s = 0; s < symbols; s++) {
3244 pr_muschar( _Cur[AX] + compensation - jam_factor,
3245 y + ((table[s + skip] + offset) * Stepsize),
3246 muschar, DFLT_SIZE, FONT_MUSIC);
3251 /* print time signature on specified staff */
3252 /* return width of what was printed */
3255 pr_timesig(staffno, x, multnum, really_print)
3257 int staffno; /* which staff to print on */
3258 double x; /* coordinate */
3259 int multnum; /* number of measures of multirest that follow */
3260 int really_print; /* if YES, actually print, else just return width */
3263 char numstr[MAXTSLEN * 3]; /* numerator as a string */
3264 char denstr[8]; /* denominator as a string */
3265 char plusstr[4]; /* plus sign as a string */
3266 float numwidth, denwidth; /* width of numstr and denstr */
3267 double thiswidth; /* width of current fraction */
3268 double totalwidth; /* width of entire time signature */
3269 double numjam, denjam; /* certain 2-digit number look better
3270 * if jammed together somewhat */
3271 char *t; /* walk through timerep */
3272 double y; /* y coordinate */
3275 if (is_tab_staff(staffno) == YES) {
3276 /* tab staffs never have a time signature */
3280 if ( Score.timevis == PTS_NEVER ) {
3285 numwidth = denwidth = thiswidth = totalwidth = numjam = denjam = 0.0;
3287 /* string version of numbers for time sig */
3288 numstr[0] = denstr[0] = plusstr[0] = FONT_NB;
3289 numstr[1] = denstr[1] = plusstr[1] = adj_size(16, Staffscale, (char *) 0, -1);
3294 for (t = Score.timerep; *t != TSR_END; t++) {
3296 if (*t == TSR_CUT || *t == TSR_COMMON) {
3299 tschar = (*t == TSR_CUT ? C_CUT : C_COM);
3300 thiswidth = width(FONT_MUSIC, DFLT_SIZE, tschar) * Staffscale;
3301 totalwidth += thiswidth;
3303 pr_muschar( x + totalwidth - (thiswidth / 2.0),
3304 Staffs_y[staffno], tschar,
3305 DFLT_SIZE, FONT_MUSIC);
3309 else if (*t == TSR_SLASH) {
3311 (void) sprintf(denstr + 2, "%d", *t);
3313 denwidth = strwidth(denstr) - denjam;
3314 numwidth = strwidth(numstr) - numjam;
3315 thiswidth = MAX(numwidth, denwidth);
3318 char onenum[8]; /* one component of numerator */
3319 int n; /* index into numstr */
3321 /* print numerator */
3322 xx = x + totalwidth +
3323 (thiswidth - numwidth)/2.0;
3324 y = Staffs_y[staffno];
3325 onenum[0] = numstr[0];
3326 onenum[1] = numstr[1];
3327 for (n = 2; numstr[n] != '\0'; n++) {
3329 if (numstr[n] == '+') {
3330 pr_string(xx, y + 2.0 * Stdpad,
3337 onenum[2] = numstr[n];
3338 if (isdigit(numstr[n+1])) {
3339 onenum[3] = numstr[++n];
3345 pr_tsnum(xx, y, onenum, tsjam(atoi(onenum + 2)));
3349 /* print denominator */
3350 y = Staffs_y[staffno] - strheight(denstr)
3352 pr_tsnum(x + totalwidth +
3353 (thiswidth - denwidth)/2.0, y,
3357 totalwidth += thiswidth;
3359 /* Reset things in case there is another
3360 * time signature component */
3361 numwidth = denwidth = 0.0;
3362 numstr[2] = denstr[2] = '\0';
3366 else if (*t == TSR_ALTERNATING) {
3367 if (Score.timevis == PTS_ALWAYS) {
3368 /* In this mode, we print alternating
3369 * time signature on each measure
3370 * explicitly, so only print the current,
3371 * except if for multirest, in which case
3372 * we print the lesser of the number of
3373 * alternate time signatures and the
3374 * number of measures of multirest. */
3375 if (--multnum <= 0) {
3380 /* add some space */
3381 /* reuse the numstr */
3384 numwidth = strwidth(numstr);
3386 pr_string(x + totalwidth,
3387 Staffs_y[staffno] - strheight(numstr)/2.0,
3388 numstr, J_LEFT, (char *) 0, -1);
3390 totalwidth += numwidth;
3391 /* reset for the next numerator */
3396 else if (*t == TSR_ADD) {
3398 pr_string(x + totalwidth,
3400 - strheight(plusstr)/2.0 + 1.5 * Stdpad,
3401 plusstr, J_LEFT, (char *) 0, -1);
3403 totalwidth += strwidth(plusstr);
3407 /* If first denominator number, use as is,
3408 * otherwise have to add a plus sign first */
3409 if (numstr[2] != '\0') {
3410 (void) strcat(numstr, "+");
3412 (void) sprintf(numstr + strlen(numstr), "%d", *t);
3413 numjam += tsjam(*t);
3417 return (totalwidth);
3421 /* Return the amount by which to jam the digits of a time signature number
3422 * together. Could be zero (if a 1-digit number or a number that doesn't
3432 /* jam numbers 10 and 13-19 together a bit */
3433 return ( (num == 10 || (num > 12 && num < 20)) ? 2.0 * Stdpad : 0.0);
3438 /* print a number that is part of a time signature. The number is passed
3439 * as a string in str, and is to be printed as the given (x,y). Some 2-digit
3440 * numbers look better if jammed together somewhat, so if jam is non-zero,
3441 * jam them by that much, else just print the str as is.
3445 pr_tsnum(x, y, str, jam)
3456 /* split and print 1 digit at a time */
3459 pr_string(x, y, str, J_LEFT, (char *) 0, -1);
3461 pr_string(_Cur[AX] - jam, y, str, J_LEFT, (char *) 0, -1);
3464 pr_string(x, y, str, J_LEFT, (char *) 0, -1);
3469 /* print a string */
3472 pr_string(x, y, string, justify, fname, lineno)
3474 double x, y; /* where to put it */
3475 char *string; /* what to print */
3476 int justify; /* J_LEFT, etc */
3477 char *fname; /* file name for error messages */
3478 int lineno; /* line number for error messages */
3481 /* This function is now just a wrapper that passes its arguments
3482 * pass to a more general function. The added -1.0 argument says
3483 * to not spread out for right justified paragraph. */
3484 pr_wstring(x, y, string, justify, -1.0, fname, lineno);
3487 /* more general string printing function that handles right justified paragraphs */
3490 pr_wstring(x, y, string, justify, fullwidth, fname, lineno)
3492 double x, y; /* where to put it */
3493 char *string; /* what to print */
3494 int justify; /* J_LEFT, etc */
3495 double fullwidth; /* width to use, or negative value to use strwidth */
3496 char *fname; /* file name for error messages */
3497 int lineno; /* line number for error messages */
3500 /* skip any empty strings */
3501 if ( ( string == (char *) 0) || (*string == '\0') ) {
3505 /* set font and size */
3506 pr_font( (int) string[0], (int) string[1]);
3508 if (IS_BOXED(string) == YES) {
3509 /* The strheight and width already include the box dimension,
3510 * so print the box of that size. Then adjust the x of
3511 * the string so it will print at the right place
3512 * inside the box. */
3513 pr_box(x + 1.5 * STDPAD, y - strdescent(string) + 3.0 * STDPAD,
3514 strheight(string) - 5.0 * STDPAD,
3515 strwidth(string) - (1.5 * STDPAD));
3520 if (IS_CIRCLED(string) == YES) {
3523 float elongation_factor;
3526 float x_center, y_center;
3528 /* determine where to place the circle and its contents */
3529 (void) circled_dimensions(string, &circ_height, &circ_width,
3530 (float *) 0, &x_offset);
3531 x_center = x + circ_width / 2.0;
3532 y_center = y + strascent(string) - strheight(string) / 2.0;
3534 /* we will fiddle with the transform matrix so do inside
3539 /* draw the outer elipse */
3540 elongation_factor = circ_width / circ_height;
3541 radius = strheight(string) / 2.0;
3542 do_scale(elongation_factor, 1.0);
3543 draw_circle(x_center / elongation_factor, y_center, radius);
3545 /* undo the outer elongation, and set for inner */
3546 do_scale(1.0 / elongation_factor, 1.0);
3547 elongation_factor = (circ_width - 1.5 * Stdpad)
3548 / (circ_height - 1.5 * Stdpad);
3549 do_scale(elongation_factor, 1.0);
3551 /* the inner circle's radius is smaller than outer */
3552 radius = radius - 0.5 * Stdpad;
3553 draw_circle(x_center / elongation_factor, y_center, radius);
3555 /* fill in the area between the inner and outer elipses */
3559 /* adjust x for where text should be printed */
3563 split_a_string(x, y, string, justify, fullwidth, fname, lineno);
3567 /* Draw a circle (or maybe elipse, if scaling is in effect) */
3570 draw_circle(x, y, radius)
3572 double x, y; /* of circle center */
3585 /* output instructions for setting font and size */
3595 /* if memory is scarce, every time we do a new font,
3596 * do it in a separate save context */
3597 if (Did_save == YES) {
3615 Font_used[font] = YES;
3619 /* print font name */
3626 OUTP(("/%s ", Fontinfo[font_index(font)].ps_name));
3630 /* split a string into lines and print each line */
3633 split_a_string(x, y, string, justify, fullwidth, fname, lineno)
3635 double x; /* coordinate at which to print string */
3637 char *string; /* what string to print */
3638 int justify; /* J_LEFT, etc */
3639 double fullwidth; /* width of (possibly multi-line) string, or -1.0
3640 * if the string width should be used. */
3641 char *fname; /* file name for error messages */
3642 int lineno; /* line number for error messages */
3645 int font, size; /* current font and size */
3646 int origfont, origsize; /* font & size at beginning of current line
3648 char *text; /* beginning of text of current line */
3649 char *p; /* pointer to current place in string */
3650 int c; /* character read from string */
3651 char *buff; /* temporary copy of one line of string */
3654 origfont = font = string[0];
3655 origsize = size = string[1];
3658 /* if centering or right justifying, will need width of entire
3659 * (possibly multi-line) string, to adjust lines within the string */
3660 if (fullwidth < 0.0) {
3661 fullwidth = strwidth(string);
3664 if (IS_BOXED(string) == YES) {
3665 /* The box printing is dealt with in pr_string(), so we
3666 * can ignore the BOX commands here (and need to, in order
3667 * to make things align properly). */
3669 fullwidth -= 7.0 * STDPAD;
3672 MALLOCA(char, buff, strlen(string) + 1);
3674 c = next_str_char(&p, &font, &size);
3675 if (c == '\n' || c == '\0') {
3676 /* end of line. Print this line. Put into
3677 * temporary buffer in case more than one line */
3678 buff[0] = (char) origfont;
3679 buff[1] = (char) origsize;
3680 (void) memcpy(buff + 2, text, (unsigned) (p - text));
3681 buff[p - text + 2] = '\0';
3682 /* On final line of a justified paragraph, we don't
3683 * want to stretch that line out, because it might
3684 * only contain a couple words. */
3685 if (justify == J_JUSTPARA && c == '\0') {
3689 j_outstring(x, y, buff, justify, fullwidth,
3692 /* prepare for next line, if any */
3696 y -= fontheight(font, size);
3698 } while (c != '\0');
3703 /* output a string segment with specified justification. If J_LEFT, just
3704 * print given string at given x, y location. If J_CENTER, put half way
3705 * between x and (x + fullwidth). If J_RIGHT, print such that right edge
3706 * of string will be at (x + fullwidth) */
3709 j_outstring(x, y, string, justify, fullwidth, fname, lineno)
3713 char *string; /* which string to print */
3714 int justify; /* J_LEFT, etc */
3715 double fullwidth; /* full width to allocate to string */
3716 char *fname; /* file name for error messages */
3717 int lineno; /* line number for error messages */
3722 /* NONE is effectively the same as LEFT */
3726 outstring(x, y, -1.0, string, fname, lineno);
3729 outstring(x, y, fullwidth, string, fname, lineno);
3732 outstring(x + (fullwidth - strwidth(string)) / 2.0, y,
3733 -1.0, string, fname, lineno);
3736 outstring(x + fullwidth - strwidth(string), y, -1.0,
3737 string, fname, lineno);
3740 pfatal("bad justification type");
3747 /* given a MAINLL struct, find all the STAFF structs from there to the next
3748 * BAR, and fill in a table of the staff Y coordinates */
3753 struct MAINLL *main_p;
3758 /* First initialize all to 0.0. This is so that if the Staffs_y
3759 * array is accessed for a non-existent staff, we will be sure
3760 * that it will be set to 0.0, which is the special value to mean
3761 * non-existent. Otherwise, when the number of staffs decreases,
3762 * an old value could get left around in the staff that went away. */
3763 for (s = 1; s <= MAXSTAFFS; s++) {
3767 for ( ; main_p != (struct MAINLL *) 0; main_p = main_p->next) {
3769 if (main_p->str == S_BAR) {
3770 /* reached end of list of staffs in this measure */
3774 if (main_p->str == S_STAFF) {
3775 /* save y value of staff */
3776 Staffs_y[main_p->u.staff_p->staffno] =
3777 main_p->u.staff_p->c[AY];
3783 /* print measure number at beginning of score if user wants them */
3786 pr_meas_num(staffno, x)
3788 int staffno; /* which staff to possible put measure number on */
3789 double x; /* where to put measure number */
3792 float y_adj; /* to avoid clefs */
3796 /* measure numbers only put on those staffs that have endings */
3797 if (has_ending(staffno) ) {
3799 /* print measure number if user wants them */
3800 if ( (svpath(staffno, MEASNUM)->measnum == YES)
3801 && (Meas_num > 1)) {
3803 /* construct the measure number string */
3805 mnumstr[0] = (char) (Score.measnumfamily
3806 + Score.measnumfont);
3807 mnumstr[1] = (char) Score.measnumsize;
3808 (void) sprintf(mnumstr + 2, "%d", Meas_num);
3811 if (is_tab_staff(staffno) == YES) {
3814 /* If clef is not to be printed, use NOCLEF.
3815 * (printclef shares the STAFFLINES used flag) */
3816 else if (svpath(staffno, STAFFLINES)->printclef == NO) {
3820 clef = svpath(staffno, CLEF)->clef;
3822 /* Figure out where to place the measure number
3823 * vertically by calling clefspace to get
3824 * the height of the clef on the current staff plus
3825 * the height of the measure number, but ignoring
3826 * the height of the clef above (if any), then
3827 * subtract the ascent of the measure number to
3828 * get the right baseline. */
3829 y_adj = halfstaffhi(staffno) +
3830 clefspace(NOCLEF, 1.0, clef, Staffscale, YES) -
3831 fontascent((int) mnumstr[0], (int) mnumstr[1]);
3832 pr_string(x + 1.5 * Stepsize,
3833 Staffs_y[staffno] + y_adj,
3834 mnumstr, J_LEFT, (char *) 0, -1);
3840 /* tell PostScript about file and linenumber */
3843 pr_linenum (inputfile, inputlineno)
3849 static char *fname = ""; /* keep track of current file
3850 * name to only output it when
3852 char *str; /* walk thru file name to
3853 * add backslashes if needed */
3856 if (strcmp(fname, inputfile) != 0) {
3858 for (str = inputfile; *str != 0; str++) {
3870 OUTP((") inputfile\n"));
3873 OUTP(("%d linenum\n", inputlineno));
3877 /* output the current scale factor */
3883 OUTP(("%f %f scale\n", Score.scale_factor, Score.scale_factor));
3887 /* For debugging, this generates PostScript to draw colored bounding boxes
3888 * representing coordinates (the 13-element arrays called "c"
3889 * in various structs).
3893 show_coord(coord_p, index)
3895 float *coord_p; /* which one to draw */
3896 int index; /* index into Bbox_list, to get colors to use */
3901 bb_p = &(Bbox_list[index]);
3903 OUTP(("%d.%d %d.%d %d.%d setrgbcolor\n",
3904 bb_p->red / 100, bb_p->red % 100,
3905 bb_p->green / 100, bb_p->green % 100,
3906 bb_p->blue / 100, bb_p->blue % 100));
3907 if (bb_p->dash_on && bb_p->dash_off) {
3908 OUTP(("[%d %d] 0 setdash\n", bb_p->dash_on, bb_p->dash_off));
3910 pr_box(coord_p[AW], coord_p[AS], coord_p[AN] - coord_p[AS], coord_p[AE] - coord_p[AW]);
3915 /* The environment variable MUP_BB turns on drawing of bounding boxes around
3916 * things, for debugging. This function checks if the variable is set,
3917 * and if so, parses it to see which subset of things to draw boxes for.
3918 * For example, MUP_BB=g just does grpsyls, whereas MUP_BB=gnc does grpsyls,
3919 * notes, and chords. Bbox_list gives the full list of possibilities.
3928 if ((bb = getenv("MUP_BB")) == 0) {
3929 /* user doesn't want bounding box debugging */
3933 /* If a coordinate type's id is set in MUP_BB, set its corresponding
3935 for (i = 0; i < NUMELEM(Bbox_list); i++) {
3936 if (strchr(bb, Bbox_list[i].id) != 0) {
3943 /* To help with debugging the placement phase of Mup,
3944 * or just to help a user see why things are laid out as they are,
3945 * this function will draw colored bounding boxes around things that
3946 * have "coordinates." The environment variable MUP_BB control which,
3947 * if any, kinds of things this is done for. This function is given the
3948 * main list item at the end of a page. It backs up through the list, back to
3949 * the beginning of the page, generating PostScript code to cause
3950 * printing of relevant boxes. Doing this last on a page ensures the boxes
3951 * are drawn on top of other things, and is at least as easy as going forwards.
3955 show_bounding_boxes(mll_p)
3957 struct MAINLL *mll_p; /* FEED for end of current page, or could be
3958 * Mainlltc_p if at end of song. */
3961 int v; /* voice/verse */
3962 int n; /* NOTE index */
3963 struct GRPSYL *gs_p;
3964 struct CHORD *chord_p;
3965 struct STUFF *stuff_p;
3967 /* We are at bottom of main list for current page. Work upwards,
3968 * printing any coords we find. */
3969 if (mll_p->str == S_FEED) {
3971 * We want to back up to previous page feed, if any */
3972 mll_p = mll_p->prev;
3975 for ( ; mll_p != 0; mll_p = mll_p->prev) {
3976 switch (mll_p->str) {
3979 if (BB_IS_SET(BB_BAR)) {
3980 show_coord(mll_p->u.bar_p->c, BB_BAR);
3985 if (BB_IS_SET(BB_FEED)) {
3986 show_coord(mll_p->u.feed_p->c, BB_FEED);
3988 if (mll_p->u.feed_p->pagefeed == YES
3989 || Feednumber == 1) {
3990 if (BB_IS_SET(BB_BLOCKHEAD)) {
3991 /* Do header/footer */
3992 if (Feednumber == 1) {
3993 show_coord(Header.c, BB_BLOCKHEAD);
3994 show_coord(Footer.c, BB_BLOCKHEAD);
3997 show_coord(Header2.c, BB_BLOCKHEAD);
3998 show_coord(Footer2.c, BB_BLOCKHEAD);
4000 if (mll_p->u.feed_p->top_p != 0){
4001 set_win_coord(mll_p->u.feed_p->top_p->c);
4002 show_coord(mll_p->u.feed_p->top_p->c, BB_BLOCKHEAD);
4005 if (mll_p->u.feed_p->bot_p != 0){
4006 set_win_coord(mll_p->u.feed_p->bot_p->c);
4007 show_coord(mll_p->u.feed_p->bot_p->c, BB_BLOCKHEAD);
4011 if (mll_p->u.feed_p->pagefeed == YES) {
4012 /* reached top of current page; we're done */
4019 if (mll_p->u.staff_p->visible == NO) {
4023 /* show the staff itself */
4024 if (BB_IS_SET(BB_STAFF)) {
4025 show_coord(mll_p->u.staff_p->c, BB_STAFF);
4028 /* Do groups and notes */
4029 if (BB_IS_SET(BB_GRPSYL) || BB_IS_SET(BB_NOTE)) {
4030 for (v = 0; v < MAXVOICES; v++) {
4032 if (vvpath(mll_p->u.staff_p->staffno,
4033 v+1, VISIBLE)->visible
4035 /* Skip invisible voices */
4039 for (gs_p = mll_p->u.staff_p->groups_p[v];
4041 gs_p = gs_p->next) {
4042 if (BB_IS_SET(BB_GRPSYL)) {
4043 show_coord(gs_p->c, BB_GRPSYL);
4045 if (gs_p->nnotes > 0 &&
4046 BB_IS_SET(BB_NOTE)) {
4047 for (n = 0; n < gs_p->nnotes; n++) {
4048 show_coord(gs_p->notelist[n].c, BB_NOTE);
4056 if (BB_IS_SET(BB_GRPSYL)) {
4057 for (n = 0; n < mll_p->u.staff_p->nsyllists; n++) {
4058 for (gs_p = mll_p->u.staff_p->syls_p[n];
4060 gs_p = gs_p->next) {
4061 show_coord(gs_p->c, BB_GRPSYL);
4066 /* do the other "stuff" */
4067 if (BB_IS_SET(BB_STUFF)) {
4068 for (stuff_p = mll_p->u.staff_p->stuff_p;
4070 stuff_p = stuff_p->next) {
4071 show_coord(stuff_p->c, BB_STUFF);
4077 if (BB_IS_SET(BB_CHORD)) {
4078 for (chord_p = mll_p->u.chhead_p->ch_p; chord_p != 0;
4079 chord_p = chord_p->ch_p) {
4080 show_coord(chord_p->c, BB_CHORD);