| 1 | |
| 2 | /* Copyright (c) 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006 by Arkkra Enterprises */ |
| 3 | /* All rights reserved */ |
| 4 | |
| 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. |
| 11 | */ |
| 12 | |
| 13 | #include <time.h> |
| 14 | #include <string.h> |
| 15 | #include "defines.h" |
| 16 | #include "structs.h" |
| 17 | #include "globals.h" |
| 18 | |
| 19 | |
| 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;} |
| 24 | |
| 25 | |
| 26 | /* the PostScript commands */ |
| 27 | #define O_FONT (1) |
| 28 | #define O_SIZE (2) |
| 29 | #define O_LINEWIDTH (3) |
| 30 | #define O_CURVETO (4) |
| 31 | #define O_DOTTED (5) |
| 32 | #define O_SHOWPAGE (6) |
| 33 | #define O_SHOW (7) |
| 34 | #define O_STAFF (8) |
| 35 | #define O_SETFONT (9) |
| 36 | #define O_MOVETO (10) |
| 37 | #define O_LINE (11) /* lineto stroke */ |
| 38 | #define O_BRACE (12) |
| 39 | #define O_BRACKET (13) |
| 40 | #define O_ENDDOTTED (14) |
| 41 | #define O_WAVY (15) |
| 42 | #define O_DASHED (16) |
| 43 | #define O_SAVE (17) |
| 44 | #define O_RESTORE (18) |
| 45 | #define O_FILL (19) |
| 46 | #define O_LINETO (20) |
| 47 | #define O_STROKE (21) |
| 48 | #define O_NEWPATH (22) |
| 49 | #define O_CLOSEPATH (23) |
| 50 | #define O_GSAVE (24) |
| 51 | #define O_GRESTORE (25) |
| 52 | #define O_CONCAT (26) |
| 53 | #define O_ARC (27) |
| 54 | #define O_EOFILL (28) |
| 55 | #define O_SCALE (29) |
| 56 | #define O_TRANSLATE (30) |
| 57 | #define O_ROTATE (31) |
| 58 | #define O_WIDTHSHOW (32) |
| 59 | #define O_ROLL (33) |
| 60 | |
| 61 | #ifdef __TURBOC__ |
| 62 | #define SMALLMEMORY 1 |
| 63 | #endif |
| 64 | |
| 65 | /* |
| 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. |
| 70 | */ |
| 71 | #define BB_BAR 0 |
| 72 | #define BB_CHORD 1 |
| 73 | #define BB_FEED 2 |
| 74 | #define BB_GRPSYL 3 |
| 75 | #define BB_BLOCKHEAD 4 |
| 76 | #define BB_NOTE 5 |
| 77 | #define BB_STAFF 6 |
| 78 | #define BB_STUFF 7 |
| 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)) |
| 82 | |
| 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. |
| 87 | */ |
| 88 | static struct Bbox { |
| 89 | char id; /* character in $MUP_BB that says to draw these */ |
| 90 | char red; /* per cent of this color to use when drawing */ |
| 91 | char green; |
| 92 | char blue; |
| 93 | char dash_on; /* for setdash */ |
| 94 | char dash_off; |
| 95 | } Bbox_list[] = { |
| 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 */ |
| 104 | }; |
| 105 | static short Do_bbox = 0; |
| 106 | |
| 107 | #ifdef SMALLMEMORY |
| 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; |
| 111 | #endif |
| 112 | |
| 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" }; |
| 119 | |
| 120 | static int Pagesprinted = 0; /* number of pages actually printed */ |
| 121 | static int Feednumber; /* how many pagefeeds we've handled */ |
| 122 | |
| 123 | |
| 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 |
| 127 | * multirest. */ |
| 128 | |
| 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 */ |
| 137 | static int sn; |
| 138 | extern int *Check_p; |
| 139 | static int Landscape; /* how much to translate for landscape |
| 140 | * mode, or 0 if not in landscape */ |
| 141 | |
| 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)); |
| 147 | #ifdef EXTCHAR |
| 148 | static void setup_extended_fonts P((void)); |
| 149 | #endif |
| 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, |
| 160 | double y2)); |
| 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, |
| 180 | int really_print)); |
| 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, |
| 184 | int really_print)); |
| 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)); |
| 201 | \f |
| 202 | |
| 203 | /* main function of print phase. Walk through main list, |
| 204 | * printing things as we go */ |
| 205 | |
| 206 | void |
| 207 | print_music() |
| 208 | |
| 209 | { |
| 210 | struct MAINLL *mll_p; /* to walk through list */ |
| 211 | struct FEED *feed_p; |
| 212 | |
| 213 | |
| 214 | debug(256, "print_music"); |
| 215 | prep_bbox(); |
| 216 | |
| 217 | /* initialize for printing */ |
| 218 | init4print(); |
| 219 | |
| 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) { |
| 223 | |
| 224 | { |
| 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))); |
| 228 | } |
| 229 | |
| 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 |
| 233 | * separately */ |
| 234 | if (mll_p->str != S_STAFF && mll_p->inputlineno > 0) { |
| 235 | pr_linenum(mll_p->inputfile, mll_p->inputlineno); |
| 236 | } |
| 237 | |
| 238 | /* call appropriate function(s) based on type */ |
| 239 | switch(mll_p->str) { |
| 240 | |
| 241 | case S_SSV: |
| 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)); |
| 248 | break; |
| 249 | |
| 250 | case S_STAFF: |
| 251 | OUTP(("%% staff %d\n", mll_p->u.staff_p->staffno)); |
| 252 | outop(O_SAVE); |
| 253 | set_staffscale(mll_p->u.staff_p->staffno); |
| 254 | pr_staff(mll_p); |
| 255 | outop(O_RESTORE); |
| 256 | Curr_font = FONT_UNKNOWN; |
| 257 | Curr_size = DFLT_SIZE; |
| 258 | Last_staff = mll_p->u.staff_p; |
| 259 | break; |
| 260 | |
| 261 | case S_BAR: |
| 262 | pr_bar(mll_p, (double)mll_p->u.bar_p->c[AX], |
| 263 | NO); |
| 264 | /* reset the staffscale to its scorewide |
| 265 | * default value */ |
| 266 | set_staffscale(0); |
| 267 | break; |
| 268 | |
| 269 | case S_CHHEAD: |
| 270 | /* nothing to do here--we print notes when we |
| 271 | * hit the S_STAFF structs */ |
| 272 | break; |
| 273 | |
| 274 | case S_PRHEAD: |
| 275 | pr_print(mll_p->u.prhead_p->printdata_p); |
| 276 | break; |
| 277 | |
| 278 | case S_LINE: |
| 279 | pr_line(mll_p->u.line_p, mll_p->inputfile, |
| 280 | mll_p->inputlineno); |
| 281 | break; |
| 282 | |
| 283 | case S_CURVE: |
| 284 | pr_curve(mll_p->u.curve_p, mll_p->inputfile, |
| 285 | mll_p->inputlineno); |
| 286 | break; |
| 287 | |
| 288 | case S_FEED: |
| 289 | pr_feed(mll_p); |
| 290 | pr_endings(mll_p); |
| 291 | break; |
| 292 | |
| 293 | case S_CLEFSIG: |
| 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) { |
| 298 | pr_reh(mll_p); |
| 299 | } |
| 300 | break; |
| 301 | |
| 302 | case S_BLOCKHEAD: |
| 303 | if (mll_p->prev == 0 || mll_p->prev->str != S_FEED) { |
| 304 | pfatal("blockhead without preceeding feed"); |
| 305 | } |
| 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); |
| 313 | set_win_coord(0); |
| 314 | break; |
| 315 | default: |
| 316 | pfatal("unknown item in main list"); |
| 317 | break; |
| 318 | } |
| 319 | } |
| 320 | |
| 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. */ |
| 334 | Do_bbox = 0; |
| 335 | } |
| 336 | pr_atend(); |
| 337 | } |
| 338 | |
| 339 | /* do final stuff for last page */ |
| 340 | pr_headfoot(Mainlltc_p); |
| 341 | } |
| 342 | \f |
| 343 | |
| 344 | /* do the things for starting a new page */ |
| 345 | void |
| 346 | newpage(mll_p) |
| 347 | |
| 348 | struct MAINLL *mll_p; |
| 349 | |
| 350 | { |
| 351 | pr_headfoot(mll_p); |
| 352 | Pagenum++; |
| 353 | to_next_page(mll_p); |
| 354 | } |
| 355 | \f |
| 356 | |
| 357 | /* print final trailer */ |
| 358 | |
| 359 | void |
| 360 | trailer() |
| 361 | |
| 362 | { |
| 363 | int f; /* font index */ |
| 364 | |
| 365 | Printflag = YES; |
| 366 | printf("%%%%Trailer\n"); |
| 367 | printf("%%%%DocumentFonts: "); |
| 368 | for (f = 1; f < MAXFONTS; f++) { |
| 369 | if (Font_used[f] == YES) { |
| 370 | prfontname(f); |
| 371 | } |
| 372 | } |
| 373 | |
| 374 | printf("\n%%%%Pages: %d\n", Score.panelsperpage == 1 ? Pagesprinted : |
| 375 | ((Pagesprinted + 1) / 2) ); |
| 376 | } |
| 377 | \f |
| 378 | |
| 379 | /* initialize things for print pass through main list */ |
| 380 | |
| 381 | static void |
| 382 | init4print() |
| 383 | |
| 384 | { |
| 385 | struct tm *timeinfo_p; |
| 386 | time_t clockinfo; |
| 387 | struct MAINLL *mll_p; |
| 388 | char *bbox_format; |
| 389 | static int first_time = YES; |
| 390 | |
| 391 | if (first_time == NO) { |
| 392 | page1setup(); |
| 393 | return; |
| 394 | } |
| 395 | first_time = NO; |
| 396 | |
| 397 | /* initialize the SSV data */ |
| 398 | initstructs(); |
| 399 | |
| 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 |
| 415 | * to get that. */ |
| 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); |
| 420 | } |
| 421 | else { |
| 422 | /* as soon as we hit something other than SSV, |
| 423 | * we're past any page size changes */ |
| 424 | break; |
| 425 | } |
| 426 | } |
| 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)); |
| 434 | } |
| 435 | else if ((Landscape = use_landscape(Score.pagewidth, Score.pageheight)) |
| 436 | != 0) { |
| 437 | printf(bbox_format, (int) (Score.pageheight * PPI), |
| 438 | (int) (Score.pagewidth * PPI)); |
| 439 | } |
| 440 | else { |
| 441 | printf(bbox_format, (int) (Score.pagewidth * PPI), |
| 442 | (int) (Score.pageheight * PPI)); |
| 443 | } |
| 444 | printf("%%%%EndComments\n"); |
| 445 | ps_prolog(); |
| 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"); |
| 542 | |
| 543 | setup_user_fonts(); |
| 544 | #ifdef EXTCHAR |
| 545 | setup_extended_fonts(); |
| 546 | #endif |
| 547 | printf("%%%%EndProlog\n"); |
| 548 | |
| 549 | /* init for first page */ |
| 550 | page1setup(); |
| 551 | } |
| 552 | \f |
| 553 | |
| 554 | /* set thing up to print the first page */ |
| 555 | |
| 556 | static void |
| 557 | page1setup() |
| 558 | |
| 559 | { |
| 560 | Feednumber = 0; |
| 561 | |
| 562 | to_next_page(Mainllhc_p); |
| 563 | |
| 564 | /* Arrange to start at beginning of main list */ |
| 565 | initstructs(); |
| 566 | |
| 567 | /* start the cursor at the top left corner of page */ |
| 568 | set_cur(0.0, PGHEIGHT); |
| 569 | |
| 570 | Meas_num = 1; |
| 571 | Ped_snapshot[0] = NO; |
| 572 | set_staffscale(0); |
| 573 | } |
| 574 | \f |
| 575 | |
| 576 | /* table of standard paper sizes, to be used to see if user specified |
| 577 | * a landscape version of a standard size */ |
| 578 | struct Papersize { |
| 579 | int width; |
| 580 | int height; |
| 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 */ |
| 590 | { 0, 0} |
| 591 | }; |
| 592 | |
| 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. */ |
| 596 | #ifdef FUZZ |
| 597 | #undef FUZZ |
| 598 | #endif |
| 599 | #define FUZZ 24 |
| 600 | |
| 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. |
| 606 | */ |
| 607 | |
| 608 | static int |
| 609 | use_landscape(pgwidth, pgheight) |
| 610 | |
| 611 | double pgwidth; /* page width in inches */ |
| 612 | double pgheight; /* page height in inches */ |
| 613 | |
| 614 | { |
| 615 | int pts_width, pts_height; /* width and height in points */ |
| 616 | int i; |
| 617 | |
| 618 | |
| 619 | /* convert dimension to points */ |
| 620 | pts_width = (int) (pgwidth * PPI); |
| 621 | pts_height = (int) (pgheight * PPI); |
| 622 | |
| 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) { |
| 631 | return(pts_height); |
| 632 | } |
| 633 | } |
| 634 | |
| 635 | /* not landscape */ |
| 636 | return(0); |
| 637 | } |
| 638 | \f |
| 639 | |
| 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. |
| 642 | */ |
| 643 | |
| 644 | static void |
| 645 | setup_user_fonts() |
| 646 | |
| 647 | { |
| 648 | int f; |
| 649 | char buffer[BUFSIZ]; |
| 650 | |
| 651 | for (f = 0; f < MAXFONTS; f++) { |
| 652 | if (Fontinfo[f].fontfile != (FILE *) 0) { |
| 653 | while (fgets(buffer, BUFSIZ, Fontinfo[f].fontfile) |
| 654 | != (char *) 0) { |
| 655 | printf("%s", buffer); |
| 656 | } |
| 657 | fclose(Fontinfo[f].fontfile); |
| 658 | } |
| 659 | } |
| 660 | } |
| 661 | \f |
| 662 | |
| 663 | #ifdef EXTCHAR |
| 664 | |
| 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. |
| 667 | */ |
| 668 | |
| 669 | static void |
| 670 | setup_extended_fonts() |
| 671 | |
| 672 | { |
| 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 */ |
| 677 | |
| 678 | |
| 679 | /* First see if there are any extended characters used at all. |
| 680 | * If not, we don't have to do anything more here */ |
| 681 | have_extended = NO; |
| 682 | for (i = FONT_TR; i <= EXT_FONT_OFFSET; i++) { |
| 683 | if (Font_used[i + EXT_FONT_OFFSET] == YES) { |
| 684 | have_extended = YES; |
| 685 | break; |
| 686 | } |
| 687 | } |
| 688 | |
| 689 | if (have_extended == NO) { |
| 690 | return; |
| 691 | } |
| 692 | |
| 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"); |
| 697 | |
| 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 |
| 705 | * is derived */ |
| 706 | prfontname(i + EXT_FONT_OFFSET); |
| 707 | prfontname(i); |
| 708 | printf("makeExtendedFont\n"); |
| 709 | } |
| 710 | } |
| 711 | } |
| 712 | #endif |
| 713 | \f |
| 714 | |
| 715 | /* given a LINE struct, output commands to draw a line */ |
| 716 | |
| 717 | static void |
| 718 | pr_line(line_p, fname, lineno) |
| 719 | |
| 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 */ |
| 723 | |
| 724 | { |
| 725 | double x1, y1; /* beginning of line */ |
| 726 | double x2, y2; /* end of line */ |
| 727 | |
| 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); |
| 732 | |
| 733 | /* If there is a string associated with the line, |
| 734 | * print that first. |
| 735 | */ |
| 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 */ |
| 739 | |
| 740 | /* First find length of line. */ |
| 741 | line_len = sqrt(SQUARED(x2 - x1) + SQUARED(y2 - y1)); |
| 742 | if (x2 < x1) { |
| 743 | line_len = -line_len; |
| 744 | } |
| 745 | |
| 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. |
| 751 | */ |
| 752 | str_x = (line_len / 2.0) - (strwidth(line_p->string) / 2.0); |
| 753 | str_y = STEPSIZE + strdescent(line_p->string); |
| 754 | |
| 755 | /* move effective origin of coordinate system to (x1,y1), |
| 756 | * then rotate by the appropriate angle and print string. |
| 757 | */ |
| 758 | outop(O_GSAVE); |
| 759 | outcoord(x1); |
| 760 | outcoord(y1); |
| 761 | outop(O_TRANSLATE); |
| 762 | /* calculate angle. If vertical line or nearly so, |
| 763 | * avoid division by zero */ |
| 764 | if (fabs(x2 - x1) < .001) { |
| 765 | outint(90); |
| 766 | } |
| 767 | else { |
| 768 | OUTP(("%.1f ", atan( (y2 - y1) / (x2 - x1) ) * 180.0 / PI)); |
| 769 | } |
| 770 | |
| 771 | outop(O_ROTATE); |
| 772 | pr_string(str_x, str_y, line_p->string, J_LEFT, 0, -1); |
| 773 | outop(O_GRESTORE); |
| 774 | } |
| 775 | |
| 776 | /* wavy lines are special case */ |
| 777 | if (line_p->linetype == L_WAVY) { |
| 778 | draw_wavy(x1, y1, x2, y2); |
| 779 | return; |
| 780 | } |
| 781 | |
| 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); |
| 785 | |
| 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); |
| 789 | } |
| 790 | } |
| 791 | \f |
| 792 | |
| 793 | /* generate PostScript command to tell what kind of line to draw */ |
| 794 | |
| 795 | void |
| 796 | do_linetype(ltype) |
| 797 | |
| 798 | int ltype; /* L_WIDE, L_NORMAL, etc */ |
| 799 | |
| 800 | { |
| 801 | if (Last_linetype == ltype && Last_staffscale == Staffscale) { |
| 802 | /* same as last time, no need to tell the printer again */ |
| 803 | return; |
| 804 | } |
| 805 | |
| 806 | /* output command for proper width/type of line */ |
| 807 | switch(ltype) { |
| 808 | |
| 809 | case L_WIDE: |
| 810 | OUTP(("%4.2f ", W_WIDE * Staffscale)); |
| 811 | outop(O_LINEWIDTH); |
| 812 | break; |
| 813 | |
| 814 | case L_NORMAL: |
| 815 | OUTP(("%4.2f ", W_NORMAL * Staffscale)); |
| 816 | outop(O_LINEWIDTH); |
| 817 | break; |
| 818 | |
| 819 | case L_MEDIUM: |
| 820 | OUTP(("%4.2f ", W_MEDIUM * Staffscale)); |
| 821 | outop(O_LINEWIDTH); |
| 822 | break; |
| 823 | |
| 824 | case L_DOTTED: |
| 825 | OUTP(("%4.2f ", Staffscale)); |
| 826 | outop(O_LINEWIDTH); |
| 827 | outop(O_DOTTED); |
| 828 | Doing_dotted = YES; |
| 829 | break; |
| 830 | |
| 831 | case L_DASHED: |
| 832 | OUTP(("%4.2f ", Staffscale)); |
| 833 | outop(O_LINEWIDTH); |
| 834 | outop(O_DASHED); |
| 835 | Doing_dotted = YES; |
| 836 | break; |
| 837 | |
| 838 | default: |
| 839 | pfatal("unknown line type"); |
| 840 | break; |
| 841 | } |
| 842 | |
| 843 | /* remember current line type */ |
| 844 | Last_linetype = ltype; |
| 845 | Last_staffscale = Staffscale; |
| 846 | |
| 847 | /* if was doing dotting but not anymore, tell PostScript */ |
| 848 | if (Doing_dotted && (ltype != L_DOTTED) && (ltype != L_DASHED)) { |
| 849 | Doing_dotted = NO; |
| 850 | outop(O_ENDDOTTED); |
| 851 | } |
| 852 | } |
| 853 | \f |
| 854 | |
| 855 | /* output commands for drawing a line. Resulting output is: |
| 856 | * x1 y1 moveto x2 y2 lineto stroke */ |
| 857 | |
| 858 | void |
| 859 | draw_line(x1, y1, x2, y2) |
| 860 | |
| 861 | double x1, y1; /* draw line from here */ |
| 862 | double x2, y2; /* to here */ |
| 863 | |
| 864 | { |
| 865 | dr_line( (double) x1, (double) y1, (double) x2, (double) y2, O_LINE); |
| 866 | } |
| 867 | |
| 868 | |
| 869 | /* output commands to draw a line whose width is proportional to the given |
| 870 | * point size */ |
| 871 | |
| 872 | void |
| 873 | draw_prop_line(x1, y1, x2, y2, size, ltype) |
| 874 | |
| 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 */ |
| 879 | |
| 880 | { |
| 881 | /* temporarily change the line width, then draw the line */ |
| 882 | outop(O_GSAVE); |
| 883 | OUTP(("%.2f ", (double) size * 0.065 * Staffscale)); |
| 884 | outop(O_LINEWIDTH); |
| 885 | dr_line(x1, y1, x2, y2, O_LINE); |
| 886 | outop(O_GRESTORE); |
| 887 | } |
| 888 | \f |
| 889 | |
| 890 | /* draw a wavy line. Resulting output is: |
| 891 | * x1 y1 moveto x2 y2 wavy */ |
| 892 | |
| 893 | void |
| 894 | draw_wavy(x1, y1, x2, y2) |
| 895 | |
| 896 | double x1; |
| 897 | double y1; /* draw wavy line from x1,y1 */ |
| 898 | double x2; |
| 899 | double y2; /* to x2, y2 */ |
| 900 | |
| 901 | { |
| 902 | dr_line((double) x1, (double) y1, (double) x2, (double) y2, O_WAVY); |
| 903 | } |
| 904 | \f |
| 905 | |
| 906 | /* actually draw line. Common function for drawing regular or wavy lines */ |
| 907 | |
| 908 | static void |
| 909 | dr_line(x1, y1, x2, y2, ltype) |
| 910 | |
| 911 | double x1; |
| 912 | double y1; /* draw line from x1,y1 */ |
| 913 | double x2; |
| 914 | double y2; /* to x2,y2 */ |
| 915 | int ltype; /* O_LINE, etc */ |
| 916 | |
| 917 | { |
| 918 | |
| 919 | /* output coordinates */ |
| 920 | outcoord(x1); |
| 921 | outcoord(y1); |
| 922 | outop(O_MOVETO); |
| 923 | |
| 924 | outcoord(x2); |
| 925 | outcoord(y2); |
| 926 | outop(ltype); |
| 927 | |
| 928 | /* current location is where line ended */ |
| 929 | set_cur(x2, y2); |
| 930 | } |
| 931 | \f |
| 932 | |
| 933 | /* output commands to draw a curve */ |
| 934 | |
| 935 | static void |
| 936 | pr_curve(curve_p, fname, lineno) |
| 937 | |
| 938 | struct CURVE *curve_p; /* which curve */ |
| 939 | char *fname; /* file name for error messages */ |
| 940 | int lineno; /* line number for error messages */ |
| 941 | |
| 942 | { |
| 943 | struct INPCOORD *inpcoord_p; |
| 944 | int n; |
| 945 | float *xlist, *ylist; |
| 946 | float cwid; /* curve width */ |
| 947 | int taper; /* YES or NO */ |
| 948 | |
| 949 | |
| 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); |
| 959 | } |
| 960 | switch(curve_p->curvetype) { |
| 961 | case L_NORMAL: |
| 962 | cwid = W_NORMAL / PPI; |
| 963 | taper = YES; |
| 964 | break; |
| 965 | case L_MEDIUM: |
| 966 | cwid = W_MEDIUM / PPI; |
| 967 | taper = YES; |
| 968 | break; |
| 969 | case L_WIDE: |
| 970 | cwid = W_WIDE / PPI; |
| 971 | taper = YES; |
| 972 | break; |
| 973 | case L_DASHED: |
| 974 | cwid = 1.0 / PPI; |
| 975 | taper = NO; |
| 976 | do_linetype(L_DASHED); |
| 977 | break; |
| 978 | case L_DOTTED: |
| 979 | cwid = 1.0 / PPI; |
| 980 | taper = NO; |
| 981 | do_linetype(L_DOTTED); |
| 982 | break; |
| 983 | default: |
| 984 | pfatal("unknown curve type"); |
| 985 | /*NOTREACHED*/ |
| 986 | return; |
| 987 | } |
| 988 | /* adjust for current staff scaling */ |
| 989 | cwid *= Staffscale; |
| 990 | |
| 991 | pr_allcurve(xlist, ylist, curve_p->ncoord, cwid, taper); |
| 992 | FREE(xlist); |
| 993 | FREE(ylist); |
| 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); |
| 997 | } |
| 998 | } |
| 999 | \f |
| 1000 | |
| 1001 | /* functions to do common PostScript things */ |
| 1002 | |
| 1003 | void |
| 1004 | do_moveto(x, y) |
| 1005 | |
| 1006 | double x; |
| 1007 | double y; |
| 1008 | |
| 1009 | { |
| 1010 | outcoord(x); |
| 1011 | outcoord(y); |
| 1012 | outop(O_MOVETO); |
| 1013 | } |
| 1014 | |
| 1015 | |
| 1016 | void |
| 1017 | do_line(x, y) |
| 1018 | |
| 1019 | double x; |
| 1020 | double y; |
| 1021 | |
| 1022 | { |
| 1023 | outcoord(x); |
| 1024 | outcoord(y); |
| 1025 | outop(O_LINETO); |
| 1026 | } |
| 1027 | |
| 1028 | void |
| 1029 | do_curveto(x1, y1, x2, y2, x3, y3) |
| 1030 | |
| 1031 | double x1, y1; |
| 1032 | double x2, y2; |
| 1033 | double x3, y3; |
| 1034 | |
| 1035 | { |
| 1036 | outcoord(x1); |
| 1037 | outcoord(y1); |
| 1038 | outcoord(x2); |
| 1039 | outcoord(y2); |
| 1040 | outcoord(x3); |
| 1041 | outcoord(y3); |
| 1042 | outop(O_CURVETO); |
| 1043 | } |
| 1044 | |
| 1045 | |
| 1046 | void |
| 1047 | do_stroke() |
| 1048 | |
| 1049 | { |
| 1050 | outop(O_STROKE); |
| 1051 | } |
| 1052 | |
| 1053 | void |
| 1054 | do_fill() |
| 1055 | |
| 1056 | { |
| 1057 | outop(O_FILL); |
| 1058 | } |
| 1059 | |
| 1060 | void |
| 1061 | do_newpath() |
| 1062 | |
| 1063 | { |
| 1064 | outop(O_NEWPATH); |
| 1065 | } |
| 1066 | |
| 1067 | void |
| 1068 | do_closepath() |
| 1069 | |
| 1070 | { |
| 1071 | outop(O_CLOSEPATH); |
| 1072 | } |
| 1073 | |
| 1074 | /* output a PostScript scale command */ |
| 1075 | |
| 1076 | static void |
| 1077 | do_scale(xscale, yscale) |
| 1078 | |
| 1079 | double xscale, yscale; |
| 1080 | |
| 1081 | { |
| 1082 | OUTP(("%0.6f %0.6f ", xscale, yscale)); |
| 1083 | outop(O_SCALE); |
| 1084 | } |
| 1085 | |
| 1086 | /* print a white box with the corners given */ |
| 1087 | |
| 1088 | void |
| 1089 | do_whitebox(x1, y1, x2, y2) |
| 1090 | |
| 1091 | double x1, y1; |
| 1092 | double x2, y2; |
| 1093 | |
| 1094 | { |
| 1095 | outcoord(x1); |
| 1096 | outcoord(y1); |
| 1097 | outcoord(x2); |
| 1098 | outcoord(y2); |
| 1099 | OUTP(("whitebox\n")); |
| 1100 | } |
| 1101 | \f |
| 1102 | |
| 1103 | /* output PostScript to draw a guitar grid */ |
| 1104 | |
| 1105 | void |
| 1106 | do_grid(x, y, space, grid_p, staff) |
| 1107 | |
| 1108 | double x; |
| 1109 | double y; |
| 1110 | double space; /* distance between lines of the grid */ |
| 1111 | struct GRID *grid_p; |
| 1112 | int staff; |
| 1113 | |
| 1114 | { |
| 1115 | int s; |
| 1116 | int fret, fretnum, numvert; |
| 1117 | int topfret; |
| 1118 | |
| 1119 | outcoord(x); |
| 1120 | outcoord(y); |
| 1121 | outcoord(space); |
| 1122 | |
| 1123 | gridinfo(grid_p, staff, &fret, &fretnum, &numvert, &topfret); |
| 1124 | outint(fret); |
| 1125 | outint(fretnum); |
| 1126 | outint(numvert); |
| 1127 | |
| 1128 | /* the curve ends */ |
| 1129 | outint(grid_p->curvel); |
| 1130 | outint(grid_p->curver); |
| 1131 | |
| 1132 | /* fret value for each string in a PostScript array */ |
| 1133 | OUTP(("[ ")); |
| 1134 | for (s = 0; s < grid_p->numstr; s++) { |
| 1135 | if (grid_p->positions[s] <= 0) { |
| 1136 | outint(grid_p->positions[s]); |
| 1137 | } |
| 1138 | else { |
| 1139 | outint(grid_p->positions[s] - topfret); |
| 1140 | } |
| 1141 | } |
| 1142 | OUTP(("] grid\n")); |
| 1143 | } |
| 1144 | \f |
| 1145 | |
| 1146 | /* output commands for printing one music character */ |
| 1147 | |
| 1148 | void |
| 1149 | pr_muschar(x, y, ch, size, font) |
| 1150 | |
| 1151 | float x, y; /* where to print */ |
| 1152 | int ch; /* which music character to print */ |
| 1153 | int size; |
| 1154 | int font; /* FONT_MUSIC* */ |
| 1155 | |
| 1156 | { |
| 1157 | outp_muschar(x, y, ch, size, font); |
| 1158 | |
| 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); |
| 1162 | } |
| 1163 | \f |
| 1164 | |
| 1165 | /* Output PostScript to print a music character. Common part for |
| 1166 | * normal and italic versions of the character. */ |
| 1167 | |
| 1168 | static void |
| 1169 | outp_muschar(x, y, ch, size, font) |
| 1170 | |
| 1171 | double x, y; |
| 1172 | int ch; |
| 1173 | int size; |
| 1174 | |
| 1175 | { |
| 1176 | double scaling; |
| 1177 | |
| 1178 | /* tell where to print it */ |
| 1179 | outcoord( (double) x); |
| 1180 | outcoord( (double) y); |
| 1181 | |
| 1182 | if (size == DFLT_SIZE) { |
| 1183 | scaling = Staffscale; |
| 1184 | } |
| 1185 | else { |
| 1186 | scaling = (double) size * Staffscale / (double) DFLT_SIZE; |
| 1187 | } |
| 1188 | OUTP(("%f ", scaling)); |
| 1189 | |
| 1190 | /* output the symbolic name of the music character */ |
| 1191 | OUTP(("%s\n", mc_num2name(ch, font))); |
| 1192 | } |
| 1193 | \f |
| 1194 | |
| 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 | * ---------- --------- |
| 1201 | * | | --> / / |
| 1202 | * | | / / |
| 1203 | * ---------- -------- |
| 1204 | */ |
| 1205 | |
| 1206 | static void |
| 1207 | pr_ital_muschar(x, y, ch, size, font) |
| 1208 | |
| 1209 | double x, y; /* where to print */ |
| 1210 | int ch; /* which music character to print */ |
| 1211 | int size; |
| 1212 | int font; /* MUSIC_FONT* */ |
| 1213 | |
| 1214 | { |
| 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 */ |
| 1219 | int eff_size; |
| 1220 | |
| 1221 | |
| 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; |
| 1230 | |
| 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; |
| 1237 | } |
| 1238 | |
| 1239 | /* Temporarily change the transform matrix. |
| 1240 | * The y value is unchanged by the transform. |
| 1241 | * The new x is |
| 1242 | * x' = ax + cy + t |
| 1243 | * where t is 0, and a and c are as stated below. |
| 1244 | */ |
| 1245 | a = (chwidth + 2 * inc - adj) / chwidth; |
| 1246 | c = adj / chheight; |
| 1247 | |
| 1248 | outop(O_GSAVE); |
| 1249 | OUTP(("[ %f 0.0 %f 1.0 0.0 0.0 ] ", a, c)); |
| 1250 | outop(O_CONCAT); |
| 1251 | |
| 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. |
| 1257 | */ |
| 1258 | outp_muschar((x - c * y) / a, y, ch, size, font); |
| 1259 | |
| 1260 | /* return to previous transform matrix */ |
| 1261 | outop(O_GRESTORE); |
| 1262 | |
| 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); |
| 1265 | } |
| 1266 | \f |
| 1267 | |
| 1268 | /* print bar line */ |
| 1269 | |
| 1270 | static void |
| 1271 | pr_bar(mll_p, x, is_pseudobar) |
| 1272 | |
| 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 */ |
| 1276 | |
| 1277 | { |
| 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 */ |
| 1283 | |
| 1284 | |
| 1285 | debug(512, "pr_bar"); |
| 1286 | |
| 1287 | if (is_pseudobar == YES) { |
| 1288 | bar_p = mll_p->u.clefsig_p->bar_p; |
| 1289 | } |
| 1290 | else { |
| 1291 | bar_p = mll_p->u.bar_p; |
| 1292 | } |
| 1293 | |
| 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. */ |
| 1301 | break; |
| 1302 | } |
| 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) { |
| 1309 | break; |
| 1310 | } |
| 1311 | if (m_p->str == S_BAR) { |
| 1312 | if (m_p->u.bar_p->bartype == RESTART) { |
| 1313 | next_is_restart = YES; |
| 1314 | } |
| 1315 | /* we've looked ahead far enough */ |
| 1316 | break; |
| 1317 | } |
| 1318 | } |
| 1319 | |
| 1320 | /* go down the bar list and the list of staffs */ |
| 1321 | for (s = 1, n = 0; n < Score.nbarst; n++) { |
| 1322 | |
| 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); |
| 1326 | } |
| 1327 | |
| 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; |
| 1332 | } |
| 1333 | |
| 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); |
| 1337 | } |
| 1338 | |
| 1339 | /* If user specified a measure number use that */ |
| 1340 | if (bar_p->mnum > 0) { |
| 1341 | Meas_num = bar_p->mnum; |
| 1342 | } |
| 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 |
| 1348 | * value */ |
| 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; |
| 1354 | } |
| 1355 | else if ((bar_p->bartype != INVISBAR) && (bar_p->bartype != RESTART) |
| 1356 | && (is_pseudobar == NO)) { |
| 1357 | /* normal case, not multirest; just increment measure number */ |
| 1358 | Meas_num++; |
| 1359 | } |
| 1360 | |
| 1361 | /* print rehearsal mark if any */ |
| 1362 | if (is_pseudobar == NO) { |
| 1363 | pr_reh(mll_p); |
| 1364 | } |
| 1365 | |
| 1366 | /* take care of pedal marks for the measure */ |
| 1367 | if (is_pseudobar == NO) { |
| 1368 | pr_ped_bar(mll_p, bar_p); |
| 1369 | } |
| 1370 | } |
| 1371 | \f |
| 1372 | |
| 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 */ |
| 1375 | |
| 1376 | static void |
| 1377 | pr_bar_range(bar_p, topstaff, botstaff, x, next_is_restart, mll_p) |
| 1378 | |
| 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 */ |
| 1385 | |
| 1386 | { |
| 1387 | float y1, y2; /* top and bottom of bar line */ |
| 1388 | float halfbarwidth; /* half the width of the bar line */ |
| 1389 | int staffno; |
| 1390 | int stafflines; |
| 1391 | |
| 1392 | |
| 1393 | /* check for null pointer to avoid core dumps */ |
| 1394 | if (Score_location_p == (float *) 0) { |
| 1395 | pfatal("can't print bar: no feed"); |
| 1396 | return; |
| 1397 | } |
| 1398 | |
| 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); |
| 1411 | } |
| 1412 | |
| 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) { |
| 1416 | struct MAINLL *m_p; |
| 1417 | |
| 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 |
| 1427 | - halfbarwidth |
| 1428 | + eos_bar_adjust(bar_p); |
| 1429 | } |
| 1430 | break; |
| 1431 | } |
| 1432 | } |
| 1433 | } |
| 1434 | |
| 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++) { |
| 1439 | |
| 1440 | /* only worry about visible staffs */ |
| 1441 | if ( (svpath(staffno, VISIBLE))->visible == YES) { |
| 1442 | |
| 1443 | stafflines = svpath(staffno, STAFFLINES)->stafflines; |
| 1444 | set_staffscale(staffno); |
| 1445 | |
| 1446 | /* if hadn't found any staff yet to bar, now we have */ |
| 1447 | if (y1 < 0.0) { |
| 1448 | if (stafflines < 2) { |
| 1449 | y1 = Staffs_y[staffno] + |
| 1450 | (2.0 * Stepsize); |
| 1451 | } |
| 1452 | else { |
| 1453 | y1 = Staffs_y[staffno] + |
| 1454 | (stafflines - 1) * Stepsize |
| 1455 | * (is_tab_staff(staffno) ? |
| 1456 | TABRATIO : 1.0); |
| 1457 | /* 2-line staffs get a bit more, so |
| 1458 | * repeat sign dots have something |
| 1459 | * to be next to */ |
| 1460 | if (stafflines == 2) { |
| 1461 | y1 += 2 * Stepsize; |
| 1462 | } |
| 1463 | } |
| 1464 | } |
| 1465 | |
| 1466 | /* this is the bottom one found so far */ |
| 1467 | if (stafflines < 2) { |
| 1468 | y2 = Staffs_y[staffno] - (2.0 * Stepsize); |
| 1469 | } |
| 1470 | else { |
| 1471 | y2 = Staffs_y[staffno] - |
| 1472 | (stafflines - 1) * Stepsize * |
| 1473 | (is_tab_staff(staffno) ? TABRATIO : 1.0); |
| 1474 | if (stafflines == 2) { |
| 1475 | y2 -= 2 * Stepsize; |
| 1476 | } |
| 1477 | } |
| 1478 | |
| 1479 | /* if repeat, print the dots */ |
| 1480 | pr_repeat_dots(bar_p->bartype, staffno, (double) x); |
| 1481 | } |
| 1482 | } |
| 1483 | |
| 1484 | /* if any were visible, we draw the bar line now */ |
| 1485 | if (y1 > 0.0) { |
| 1486 | draw_bar(bar_p->bartype, bar_p->linetype, |
| 1487 | (double) x, (double) y1, (double) y2); |
| 1488 | } |
| 1489 | } |
| 1490 | \f |
| 1491 | |
| 1492 | /* actually draw a bar line of the proper type at specified place */ |
| 1493 | |
| 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() */ |
| 1497 | |
| 1498 | static void |
| 1499 | draw_bar(bartype, linetype, x, y1, y2) |
| 1500 | |
| 1501 | int bartype; /* info about single, double, repeat, etc */ |
| 1502 | int linetype; |
| 1503 | double x; |
| 1504 | double y1; /* top of bar line */ |
| 1505 | double y2; /* bottom of bar line */ |
| 1506 | |
| 1507 | { |
| 1508 | /* always use default staffscale for bar lines since they are |
| 1509 | * not associated with any particular staff */ |
| 1510 | set_staffscale(0); |
| 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; |
| 1516 | } |
| 1517 | |
| 1518 | switch (bartype) { |
| 1519 | |
| 1520 | case DOUBLEBAR: |
| 1521 | draw_line(x - 2.0 * STDPAD, y1, x - 2.0 * STDPAD, y2); |
| 1522 | draw_line(x + STDPAD, y1, x + STDPAD, y2); |
| 1523 | break; |
| 1524 | |
| 1525 | case SINGLEBAR: |
| 1526 | draw_line(x, y1, x, y2); |
| 1527 | break; |
| 1528 | |
| 1529 | case REPEATSTART: |
| 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); |
| 1533 | break; |
| 1534 | |
| 1535 | case REPEATEND: |
| 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 ); |
| 1539 | break; |
| 1540 | |
| 1541 | case REPEATBOTH: |
| 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); |
| 1545 | break; |
| 1546 | |
| 1547 | case ENDBAR: |
| 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); |
| 1551 | break; |
| 1552 | |
| 1553 | case RESTART: |
| 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. */ |
| 1556 | break; |
| 1557 | |
| 1558 | case INVISBAR: |
| 1559 | /* nothing to do! */ |
| 1560 | break; |
| 1561 | |
| 1562 | default: |
| 1563 | pfatal("bad bar type"); |
| 1564 | } |
| 1565 | do_linetype(L_NORMAL); |
| 1566 | } |
| 1567 | \f |
| 1568 | |
| 1569 | /* print the dots for a repeat sign */ |
| 1570 | |
| 1571 | static void |
| 1572 | pr_repeat_dots(bartype, staff, x) |
| 1573 | |
| 1574 | int bartype; /* repeatstart, repeatend, repeatboth, etc */ |
| 1575 | int staff; /* which staff to print on */ |
| 1576 | double x; /* horizontal position */ |
| 1577 | |
| 1578 | { |
| 1579 | float y; /* vertical position of middle of staff */ |
| 1580 | double topoffset, bottomoffset; /* dot offset */ |
| 1581 | double adjust; /* adjustment for tablature and/or staffscale */ |
| 1582 | int stafflines; |
| 1583 | |
| 1584 | |
| 1585 | /* If no dots, don't bother */ |
| 1586 | if (bartype != REPEATSTART && bartype != REPEATEND |
| 1587 | && bartype != REPEATBOTH) { |
| 1588 | return; |
| 1589 | } |
| 1590 | |
| 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"); |
| 1594 | return; |
| 1595 | } |
| 1596 | |
| 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; |
| 1601 | |
| 1602 | /* if even number of staff lines, compensate by moving up */ |
| 1603 | stafflines = svpath(staff, STAFFLINES)->stafflines; |
| 1604 | if ( (stafflines & 1) == 0) { |
| 1605 | y += adjust; |
| 1606 | } |
| 1607 | |
| 1608 | /* if more than 5 lines on staff, leave one blank space between |
| 1609 | * the dots */ |
| 1610 | if (stafflines > 5) { |
| 1611 | if ( (stafflines & 1) == 0) { |
| 1612 | /* even number of staff lines, move bottom down */ |
| 1613 | bottomoffset = 3 * adjust; |
| 1614 | } |
| 1615 | else { |
| 1616 | /* odd number of lines, move top up */ |
| 1617 | topoffset = 3 * adjust; |
| 1618 | } |
| 1619 | } |
| 1620 | |
| 1621 | |
| 1622 | /* print dots at appropriate locations */ |
| 1623 | switch(bartype) { |
| 1624 | |
| 1625 | case REPEATSTART: |
| 1626 | do_rdots((double) (x + (4.0 * STDPAD)), (double) y, topoffset, |
| 1627 | bottomoffset); |
| 1628 | break; |
| 1629 | |
| 1630 | case REPEATBOTH: |
| 1631 | do_rdots((double) (x + (7.0 * STDPAD)), (double) y, topoffset, |
| 1632 | bottomoffset); |
| 1633 | do_rdots((double) (x - (7.0 * STDPAD)), (double) y, topoffset, |
| 1634 | bottomoffset); |
| 1635 | break; |
| 1636 | |
| 1637 | case REPEATEND: |
| 1638 | do_rdots((double) (x - (4.0 * STDPAD)), (double) y, topoffset, |
| 1639 | bottomoffset); |
| 1640 | break; |
| 1641 | |
| 1642 | default: |
| 1643 | /* other types of bars don't have dots */ |
| 1644 | break; |
| 1645 | } |
| 1646 | } |
| 1647 | \f |
| 1648 | |
| 1649 | /* print the 2 dots for a repeat sign */ |
| 1650 | |
| 1651 | static void |
| 1652 | do_rdots(x, y, topoffset, bottomoffset) |
| 1653 | |
| 1654 | double x; |
| 1655 | double y; /* y is a middle of staff, so offset from there */ |
| 1656 | double topoffset, bottomoffset; /* offset from y in each direction */ |
| 1657 | |
| 1658 | { |
| 1659 | pr_muschar(x, y + topoffset, C_DOT, DFLT_SIZE, FONT_MUSIC); |
| 1660 | pr_muschar(x, y - bottomoffset, C_DOT, DFLT_SIZE, FONT_MUSIC); |
| 1661 | } |
| 1662 | \f |
| 1663 | |
| 1664 | /* print any rehearsal marks associated with bar line */ |
| 1665 | |
| 1666 | static void |
| 1667 | pr_reh(mll_p) |
| 1668 | |
| 1669 | struct MAINLL *mll_p; /* current bar line is off of here */ |
| 1670 | |
| 1671 | { |
| 1672 | struct MARKCOORD *mark_p; /* where to put rehearsal mark */ |
| 1673 | float y; /* vertical location */ |
| 1674 | struct BAR *bar_p; |
| 1675 | char *str; /* the string, with box or circle |
| 1676 | * or nothing as appropriate for |
| 1677 | * the associated staff */ |
| 1678 | |
| 1679 | |
| 1680 | if (mll_p->str == S_BAR) { |
| 1681 | bar_p = mll_p->u.bar_p; |
| 1682 | } |
| 1683 | else { |
| 1684 | bar_p = mll_p->u.clefsig_p->bar_p; |
| 1685 | } |
| 1686 | |
| 1687 | for (mark_p = bar_p->reh_p; mark_p != (struct MARKCOORD *) 0; |
| 1688 | mark_p = mark_p->next) { |
| 1689 | |
| 1690 | /* print rehearsal mark if any */ |
| 1691 | if (bar_p->reh_string != (char *) 0) { |
| 1692 | |
| 1693 | y = Staffs_y[mark_p->staffno] + mark_p->ry; |
| 1694 | |
| 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); |
| 1700 | } |
| 1701 | } |
| 1702 | } |
| 1703 | \f |
| 1704 | |
| 1705 | /* draw a box of given size at given x,y */ |
| 1706 | |
| 1707 | static void |
| 1708 | pr_box(x, y, boxheight, boxwidth) |
| 1709 | |
| 1710 | double x, y; |
| 1711 | double boxheight, boxwidth; |
| 1712 | |
| 1713 | { |
| 1714 | do_linetype(L_NORMAL); |
| 1715 | do_newpath(); |
| 1716 | do_moveto(x, y); |
| 1717 | do_line(x, y + boxheight); |
| 1718 | do_line(x + boxwidth, y + boxheight); |
| 1719 | do_line(x + boxwidth, y); |
| 1720 | do_closepath(); |
| 1721 | do_stroke(); |
| 1722 | } |
| 1723 | \f |
| 1724 | |
| 1725 | /* do a feed (newscore and maybe newpage) */ |
| 1726 | |
| 1727 | void |
| 1728 | pr_feed(main_feed_p) |
| 1729 | |
| 1730 | struct MAINLL *main_feed_p; /* MAINLL struct pointing to FEED */ |
| 1731 | |
| 1732 | { |
| 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; |
| 1741 | int stafflines; |
| 1742 | double y; |
| 1743 | |
| 1744 | |
| 1745 | debug(256, "pr_feed lineno=%d", main_feed_p->inputlineno); |
| 1746 | |
| 1747 | feed_p = main_feed_p->u.feed_p; |
| 1748 | |
| 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. */ |
| 1755 | return; |
| 1756 | } |
| 1757 | |
| 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); |
| 1762 | } |
| 1763 | |
| 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. |
| 1768 | */ |
| 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); |
| 1773 | } |
| 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); |
| 1778 | } |
| 1779 | |
| 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 */ |
| 1783 | return; |
| 1784 | } |
| 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. */ |
| 1788 | return; |
| 1789 | } |
| 1790 | |
| 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); |
| 1796 | |
| 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) { |
| 1802 | Meas_num--; |
| 1803 | } |
| 1804 | } |
| 1805 | |
| 1806 | /* for each staff */ |
| 1807 | for ( printed = 0, s = 1; s <= Score.staffs; s++) { |
| 1808 | |
| 1809 | /* print if visible */ |
| 1810 | if ( (svpath(s, VISIBLE))->visible == YES) { |
| 1811 | |
| 1812 | stafflines = svpath(s, STAFFLINES)->stafflines; |
| 1813 | set_staffscale(s); |
| 1814 | if (stafflines < 3) { |
| 1815 | lowest_y = Staffs_y[s] - (2.0 * Stepsize) |
| 1816 | * (is_tab_staff(s) ? TABRATIO : 1.0); |
| 1817 | } |
| 1818 | else { |
| 1819 | lowest_y = Staffs_y[s] - (stafflines - 1) |
| 1820 | * Stepsize * (is_tab_staff(s) ? |
| 1821 | TABRATIO : 1.0); |
| 1822 | } |
| 1823 | |
| 1824 | /* find the top of the score */ |
| 1825 | if (printed == 0) { |
| 1826 | if (stafflines < 3) { |
| 1827 | highest_y = Staffs_y[s] |
| 1828 | + (2.0 * Stepsize) |
| 1829 | * (is_tab_staff(s) ? TABRATIO : 1.0); |
| 1830 | } |
| 1831 | else { |
| 1832 | highest_y = Staffs_y[s] |
| 1833 | + (stafflines - 1) |
| 1834 | * Stepsize * (is_tab_staff(s) ? |
| 1835 | TABRATIO : 1.0); |
| 1836 | } |
| 1837 | } |
| 1838 | |
| 1839 | printed++; |
| 1840 | |
| 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), |
| 1846 | Staffscale)); |
| 1847 | outop(O_STAFF); |
| 1848 | |
| 1849 | /* print measure number at beginning of staff if |
| 1850 | * necessary */ |
| 1851 | pr_meas_num(s, Score_location_p[AX]); |
| 1852 | } |
| 1853 | } |
| 1854 | |
| 1855 | /* print brace/bracket and group label */ |
| 1856 | had_br_br = pr_brac(NO, 0.0, main_feed_p); |
| 1857 | |
| 1858 | if (printed == 0) { |
| 1859 | /* we check for this earlier, so should never hit this */ |
| 1860 | pfatal("no staffs visible"); |
| 1861 | } |
| 1862 | |
| 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); |
| 1870 | } |
| 1871 | |
| 1872 | pr_restarts(main_feed_p, highest_y, lowest_y, need_vert_line); |
| 1873 | |
| 1874 | /* set current to x,y of score */ |
| 1875 | set_cur(Score_location_p[AX], Score_location_p[AY]); |
| 1876 | } |
| 1877 | \f |
| 1878 | |
| 1879 | /* Given a BLOCKHEAD for a top/bottom and a y location, print the |
| 1880 | * contents of the BLOCKHEAD at that location. |
| 1881 | */ |
| 1882 | |
| 1883 | static |
| 1884 | void pr_topbot(blockhead_p, y) |
| 1885 | |
| 1886 | struct BLOCKHEAD *blockhead_p; |
| 1887 | double y; |
| 1888 | |
| 1889 | { |
| 1890 | double x; |
| 1891 | |
| 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); |
| 1896 | set_cur(x, y); |
| 1897 | pr_print(blockhead_p->printdata_p); |
| 1898 | set_win_coord(0); |
| 1899 | } |
| 1900 | \f |
| 1901 | |
| 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. |
| 1906 | */ |
| 1907 | |
| 1908 | static void |
| 1909 | pr_restarts(mll_p, y1, y2, need_vert_line) |
| 1910 | |
| 1911 | struct MAINLL *mll_p; |
| 1912 | double y1; |
| 1913 | double y2; |
| 1914 | int need_vert_line; |
| 1915 | |
| 1916 | { |
| 1917 | double x; |
| 1918 | |
| 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 */ |
| 1923 | return; |
| 1924 | } |
| 1925 | |
| 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, |
| 1932 | y1 + POINT, |
| 1933 | x + HALF_RESTART_WIDTH, y2 - POINT); |
| 1934 | |
| 1935 | /* print braces/brackets */ |
| 1936 | pr_brac(YES, x + POINT, mll_p); |
| 1937 | |
| 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); |
| 1943 | } |
| 1944 | |
| 1945 | } |
| 1946 | } |
| 1947 | } |
| 1948 | \f |
| 1949 | |
| 1950 | /* print a brace or bracket */ |
| 1951 | |
| 1952 | void |
| 1953 | do_pr_brac(x, y1, y2, which) |
| 1954 | |
| 1955 | double x; /* coordinates at which to draw brace or bracket */ |
| 1956 | double y1; |
| 1957 | double y2; |
| 1958 | int which; /* BRACELIST or BRACKLIST */ |
| 1959 | |
| 1960 | { |
| 1961 | outcoord(x); |
| 1962 | outcoord(y1); |
| 1963 | outcoord(y2); |
| 1964 | outop( which == BRACELIST ? O_BRACE : O_BRACKET); |
| 1965 | } |
| 1966 | \f |
| 1967 | |
| 1968 | /* output a coordinate. Convert from inches to points, to 0.01 point accuracy */ |
| 1969 | |
| 1970 | void |
| 1971 | outcoord(val) |
| 1972 | |
| 1973 | double val; /* an x or y value */ |
| 1974 | |
| 1975 | { |
| 1976 | OUTP(("%.2f ", val * PPI)); |
| 1977 | } |
| 1978 | \f |
| 1979 | |
| 1980 | |
| 1981 | /* output an integer value */ |
| 1982 | |
| 1983 | static void |
| 1984 | outint(val) |
| 1985 | |
| 1986 | int val; |
| 1987 | |
| 1988 | { |
| 1989 | OUTP(("%d ", val)); |
| 1990 | } |
| 1991 | \f |
| 1992 | |
| 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 */ |
| 1996 | |
| 1997 | static void |
| 1998 | outstring(x, y, fullwidth, string, fname, lineno) |
| 1999 | |
| 2000 | double x; /* where to print string */ |
| 2001 | double y; |
| 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 */ |
| 2010 | |
| 2011 | { |
| 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 */ |
| 2023 | int in_pile = NO; |
| 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 |
| 2027 | * matching ')' */ |
| 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; |
| 2040 | |
| 2041 | |
| 2042 | /* go to starting point of string */ |
| 2043 | outcoord( (double) x); |
| 2044 | outcoord( (double) y); |
| 2045 | outop(O_MOVETO); |
| 2046 | set_cur(x, y); |
| 2047 | |
| 2048 | /* check if consists solely of music character */ |
| 2049 | only_mus_sym = is_music_symbol(string); |
| 2050 | |
| 2051 | intrinsic_width = strwidth(string); |
| 2052 | if (lineno > 0) { |
| 2053 | if (x + intrinsic_width > PGWIDTH || x < 0.0) { |
| 2054 | l_warning(fname, lineno, |
| 2055 | "string extends beyond edge of page"); |
| 2056 | } |
| 2057 | } |
| 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 */ |
| 2062 | |
| 2063 | /* count how many spaces there are that we can stretch */ |
| 2064 | count = 0; |
| 2065 | font = *string; |
| 2066 | size = *(string + 1); |
| 2067 | s = string + 2; |
| 2068 | while ((code = next_str_char(&s, &font, &size) & 0xff) > 0) { |
| 2069 | if (code == ' ' && ! IS_MUSIC_FONT(font)) { |
| 2070 | count++; |
| 2071 | } |
| 2072 | } |
| 2073 | if (count > 0) { |
| 2074 | /* We have at least one space. Apportion needed |
| 2075 | * padding among the number of space chars. */ |
| 2076 | space_adjust = (fullwidth - intrinsic_width) / |
| 2077 | (double) count; |
| 2078 | if (space_adjust < 0.0) { |
| 2079 | /* Hmmm. Apparently string is already |
| 2080 | * wider than it should be, so leave as is. */ |
| 2081 | space_adjust = 0.0; |
| 2082 | } |
| 2083 | } |
| 2084 | } |
| 2085 | |
| 2086 | #ifdef SMALLMEMORY |
| 2087 | /* to make sure string space is cleaned up as soon as possible, |
| 2088 | * output the string inside a save/restore */ |
| 2089 | outop(O_SAVE); |
| 2090 | #endif |
| 2091 | |
| 2092 | /* walk through and output chars one at a time */ |
| 2093 | font = *string; |
| 2094 | size = *(string + 1); |
| 2095 | string += 2; |
| 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] ); |
| 2104 | outop(O_MOVETO); |
| 2105 | in_digit_string = NO; |
| 2106 | } |
| 2107 | |
| 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"); |
| 2112 | } |
| 2113 | |
| 2114 | /* draw the slash */ |
| 2115 | in_string = end_string(in_string, space_adjust); |
| 2116 | save_y = _Cur[AY]; |
| 2117 | draw_prop_line(slash_x, slash_y, _Cur[AX], |
| 2118 | _Cur[AY] + 0.6 * fontascent(font, size), |
| 2119 | size, O_LINE); |
| 2120 | set_cur(_Cur[AX], save_y); |
| 2121 | outcoord( _Cur[AX] ); |
| 2122 | outcoord( _Cur[AY] ); |
| 2123 | outop(O_MOVETO); |
| 2124 | in_digit_string = NO; |
| 2125 | continue; |
| 2126 | } |
| 2127 | |
| 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 */ |
| 2136 | slash_x = _Cur[AX]; |
| 2137 | slash_y = _Cur[AY] + |
| 2138 | 0.2 * fontascent(font, size); |
| 2139 | } |
| 2140 | } |
| 2141 | else { |
| 2142 | in_digit_string = NO; |
| 2143 | } |
| 2144 | |
| 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); |
| 2150 | |
| 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 |
| 2159 | * characters. */ |
| 2160 | save_y = _Cur[AY]; |
| 2161 | if (only_mus_sym == YES) { |
| 2162 | mussym_compensation = 0.0; |
| 2163 | } |
| 2164 | else { |
| 2165 | mussym_compensation = descent( |
| 2166 | font, size, code) - STDPAD; |
| 2167 | } |
| 2168 | /* music characters embedded inside strings will have |
| 2169 | * already been size adjusted, so compensate. */ |
| 2170 | save_staffscale = Staffscale; |
| 2171 | Staffscale = 1.0; |
| 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, |
| 2176 | code, size, font); |
| 2177 | } |
| 2178 | else { |
| 2179 | pr_muschar(_Cur[AX] + |
| 2180 | width(font, size, code)/2.0, |
| 2181 | _Cur[AY] + mussym_compensation, |
| 2182 | code, size, font); |
| 2183 | } |
| 2184 | Staffscale = save_staffscale; |
| 2185 | |
| 2186 | set_cur(_Cur[AX], save_y); |
| 2187 | outcoord( _Cur[AX] ); |
| 2188 | outcoord( _Cur[AY] ); |
| 2189 | outop(O_MOVETO); |
| 2190 | continue; |
| 2191 | } |
| 2192 | |
| 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); |
| 2197 | } |
| 2198 | |
| 2199 | switch (code) { |
| 2200 | |
| 2201 | case '(': |
| 2202 | case ')': |
| 2203 | case '\\': |
| 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]); |
| 2208 | break; |
| 2209 | |
| 2210 | case '\b': |
| 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] ); |
| 2216 | outop(O_MOVETO); |
| 2217 | break; |
| 2218 | |
| 2219 | case '%': |
| 2220 | case '#': |
| 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 |
| 2225 | * the % or #. */ |
| 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))); |
| 2232 | |
| 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), |
| 2240 | _Cur[AY]); |
| 2241 | break; |
| 2242 | } |
| 2243 | /* otherwise fall through to normal default case */ |
| 2244 | /*FALLTHRU*/ |
| 2245 | |
| 2246 | default: |
| 2247 | if (code != '\n') { |
| 2248 | /* ordinary character */ |
| 2249 | in_string = begin_string(in_string); |
| 2250 | OUTPCH(((unsigned char)code)); |
| 2251 | set_cur(_Cur[AX] + width(font, size, code), |
| 2252 | _Cur[AY]); |
| 2253 | } |
| 2254 | break; |
| 2255 | } |
| 2256 | } |
| 2257 | |
| 2258 | (void) end_string(in_string, space_adjust); |
| 2259 | #ifdef SMALLMEMORY |
| 2260 | outop(O_RESTORE); |
| 2261 | #endif |
| 2262 | } |
| 2263 | \f |
| 2264 | |
| 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 */ |
| 2268 | |
| 2269 | static int |
| 2270 | begin_string(in_string) |
| 2271 | |
| 2272 | int in_string; /* NO if not currently inside a string */ |
| 2273 | |
| 2274 | { |
| 2275 | if (in_string == NO) { |
| 2276 | OUTPCH(('(')); |
| 2277 | } |
| 2278 | return(YES); |
| 2279 | } |
| 2280 | \f |
| 2281 | |
| 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 */ |
| 2284 | |
| 2285 | static int |
| 2286 | end_string(in_string, space_adjust) |
| 2287 | |
| 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 */ |
| 2291 | |
| 2292 | { |
| 2293 | if (in_string == YES) { |
| 2294 | OUTP((") ")); |
| 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. */ |
| 2302 | outop(O_SHOW); |
| 2303 | } |
| 2304 | else { |
| 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. |
| 2311 | */ |
| 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 */ |
| 2317 | outop(O_ROLL); |
| 2318 | outop(O_WIDTHSHOW); |
| 2319 | } |
| 2320 | } |
| 2321 | return(NO); |
| 2322 | } |
| 2323 | \f |
| 2324 | |
| 2325 | /* output a postscript operator */ |
| 2326 | |
| 2327 | static void |
| 2328 | outop(op) |
| 2329 | |
| 2330 | int op; /* which operator */ |
| 2331 | |
| 2332 | { |
| 2333 | switch (op) { |
| 2334 | |
| 2335 | case O_FONT: |
| 2336 | OUTP(("findfont\n")); |
| 2337 | break; |
| 2338 | |
| 2339 | case O_SETFONT: |
| 2340 | OUTP(("setfont\n")); |
| 2341 | break; |
| 2342 | |
| 2343 | case O_SIZE: |
| 2344 | OUTP(("scalefont\n")); |
| 2345 | break; |
| 2346 | |
| 2347 | case O_LINE: |
| 2348 | OUTP(("lineto stroke\n")); |
| 2349 | break; |
| 2350 | |
| 2351 | case O_WAVY: |
| 2352 | OUTP(("%f wavy\n", Staffscale)); |
| 2353 | break; |
| 2354 | |
| 2355 | case O_CURVETO: |
| 2356 | OUTP(("curveto\n")); |
| 2357 | break; |
| 2358 | |
| 2359 | case O_LINEWIDTH: |
| 2360 | OUTP(("setlinewidth\n")); |
| 2361 | break; |
| 2362 | |
| 2363 | case O_DOTTED: |
| 2364 | OUTP(("[0.1 5] 0 setdash\n")); |
| 2365 | OUTP(("1 setlinecap\n")); |
| 2366 | OUTP(("1 setlinejoin\n")); |
| 2367 | break; |
| 2368 | |
| 2369 | case O_DASHED: |
| 2370 | OUTP(("[3 3] 0 setdash\n")); |
| 2371 | break; |
| 2372 | |
| 2373 | case O_ENDDOTTED: |
| 2374 | OUTP(("[] 0 setdash\n")); |
| 2375 | OUTP(("0 setlinecap\n")); |
| 2376 | OUTP(("0 setlinejoin\n")); |
| 2377 | break; |
| 2378 | |
| 2379 | case O_LINETO: |
| 2380 | OUTP(("lineto\n")); |
| 2381 | break; |
| 2382 | |
| 2383 | case O_SHOWPAGE: |
| 2384 | OUTP(("showpage\n")); |
| 2385 | break; |
| 2386 | |
| 2387 | case O_SHOW: |
| 2388 | OUTP(("show\n")); |
| 2389 | break; |
| 2390 | |
| 2391 | case O_WIDTHSHOW: |
| 2392 | OUTP(("widthshow\n")); |
| 2393 | break; |
| 2394 | |
| 2395 | case O_ROLL: |
| 2396 | OUTP(("roll\n")); |
| 2397 | break; |
| 2398 | |
| 2399 | case O_STAFF: |
| 2400 | OUTP(("stf\n")); |
| 2401 | break; |
| 2402 | |
| 2403 | case O_MOVETO: |
| 2404 | OUTP(("moveto\n")); |
| 2405 | break; |
| 2406 | |
| 2407 | case O_BRACE: |
| 2408 | OUTP(("brace\n")); |
| 2409 | break; |
| 2410 | |
| 2411 | case O_BRACKET: |
| 2412 | OUTP(("bracket\n")); |
| 2413 | break; |
| 2414 | |
| 2415 | case O_SAVE: |
| 2416 | OUTP(("save\n")); |
| 2417 | break; |
| 2418 | |
| 2419 | case O_RESTORE: |
| 2420 | OUTP(("restore\n")); |
| 2421 | Last_linetype = -1; |
| 2422 | break; |
| 2423 | |
| 2424 | case O_GSAVE: |
| 2425 | OUTP(("gsave\n")); |
| 2426 | break; |
| 2427 | |
| 2428 | case O_GRESTORE: |
| 2429 | OUTP(("grestore\n")); |
| 2430 | Last_linetype = -1; |
| 2431 | break; |
| 2432 | |
| 2433 | case O_CONCAT: |
| 2434 | OUTP(("concat\n")); |
| 2435 | break; |
| 2436 | |
| 2437 | case O_TRANSLATE: |
| 2438 | OUTP(("translate\n")); |
| 2439 | break; |
| 2440 | |
| 2441 | case O_ROTATE: |
| 2442 | OUTP(("rotate\n")); |
| 2443 | break; |
| 2444 | |
| 2445 | case O_SCALE: |
| 2446 | OUTP(("scale\n")); |
| 2447 | break; |
| 2448 | |
| 2449 | case O_ARC: |
| 2450 | OUTP(("arc\n")); |
| 2451 | break; |
| 2452 | |
| 2453 | case O_EOFILL: |
| 2454 | OUTP(("eofill\n")); |
| 2455 | break; |
| 2456 | |
| 2457 | case O_FILL: |
| 2458 | OUTP(("fill\n")); |
| 2459 | break; |
| 2460 | |
| 2461 | case O_STROKE: |
| 2462 | OUTP(("stroke\n")); |
| 2463 | break; |
| 2464 | |
| 2465 | case O_NEWPATH: |
| 2466 | OUTP(("newpath\n")); |
| 2467 | break; |
| 2468 | |
| 2469 | case O_CLOSEPATH: |
| 2470 | OUTP(("closepath\n")); |
| 2471 | break; |
| 2472 | |
| 2473 | default: |
| 2474 | pfatal("unknown output operator %d", op); |
| 2475 | break; |
| 2476 | } |
| 2477 | } |
| 2478 | \f |
| 2479 | |
| 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. */ |
| 2484 | |
| 2485 | static void |
| 2486 | pr_headfoot(mll_p) |
| 2487 | |
| 2488 | struct MAINLL *mll_p; |
| 2489 | |
| 2490 | { |
| 2491 | struct BLOCKHEAD *header_p; |
| 2492 | struct BLOCKHEAD *footer_p; |
| 2493 | |
| 2494 | |
| 2495 | OUTP(("%% Printing header/footer\n")); |
| 2496 | if (Do_bbox && mll_p != 0) { |
| 2497 | show_bounding_boxes(mll_p); |
| 2498 | } |
| 2499 | |
| 2500 | /* figure out which header to use */ |
| 2501 | if (Feednumber == 1) { |
| 2502 | header_p = &Header; |
| 2503 | Context = C_HEADER; |
| 2504 | } |
| 2505 | else { |
| 2506 | header_p = &Header2; |
| 2507 | Context = C_HEAD2; |
| 2508 | } |
| 2509 | |
| 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); |
| 2514 | } |
| 2515 | |
| 2516 | /* figure out which footer to use */ |
| 2517 | if (Feednumber == 1) { |
| 2518 | footer_p = &Footer; |
| 2519 | Context = C_FOOTER; |
| 2520 | } |
| 2521 | else { |
| 2522 | footer_p = &Footer2; |
| 2523 | Context = C_FOOT2; |
| 2524 | } |
| 2525 | |
| 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); |
| 2531 | } |
| 2532 | |
| 2533 | Context = C_MUSIC; |
| 2534 | |
| 2535 | /* end this page */ |
| 2536 | #ifdef SMALLMEMORY |
| 2537 | if (Did_save == YES) { |
| 2538 | outop(O_RESTORE); |
| 2539 | Did_save = NO; |
| 2540 | } |
| 2541 | #endif |
| 2542 | if ( (Score.panelsperpage < 2) || ((Pagesprinted & 1) == 0) || |
| 2543 | (last_page() == YES) ) { |
| 2544 | outop(O_SHOWPAGE); |
| 2545 | } |
| 2546 | outop(O_RESTORE); |
| 2547 | } |
| 2548 | \f |
| 2549 | |
| 2550 | /* go to next page */ |
| 2551 | |
| 2552 | static void |
| 2553 | to_next_page(mll_p) |
| 2554 | |
| 2555 | struct MAINLL *mll_p; |
| 2556 | |
| 2557 | { |
| 2558 | double headheight; |
| 2559 | double footheight; |
| 2560 | double topheight; |
| 2561 | double botheight; |
| 2562 | |
| 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; |
| 2567 | } |
| 2568 | else { |
| 2569 | headheight = Header2.height; |
| 2570 | footheight = Footer2.height; |
| 2571 | } |
| 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) { |
| 2575 | ; |
| 2576 | } |
| 2577 | if (mll_p != 0) { |
| 2578 | if (mll_p->u.feed_p->top_p != 0) { |
| 2579 | topheight = mll_p->u.feed_p->top_p->height; |
| 2580 | } |
| 2581 | if (mll_p->u.feed_p->bot_p != 0) { |
| 2582 | botheight = mll_p->u.feed_p->bot_p->height; |
| 2583 | } |
| 2584 | } |
| 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)); |
| 2589 | |
| 2590 | if ((Printflag = onpagelist(Pagenum)) == YES) { |
| 2591 | Pagesprinted++; |
| 2592 | if (Score.panelsperpage < 2) { |
| 2593 | OUTP(("%%%%Page: %d %d\n", Pagenum, Pagesprinted)); |
| 2594 | } |
| 2595 | else if ((Pagesprinted & 1) == 1) { |
| 2596 | OUTP(("%%%%Page: %d %d\n", Pagenum, (Pagesprinted + 1) / 2)); |
| 2597 | } |
| 2598 | outop(O_SAVE); |
| 2599 | sn = rand(); |
| 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")); |
| 2607 | outint(Landscape); |
| 2608 | outint(0); |
| 2609 | outop(O_TRANSLATE); |
| 2610 | outint(90); |
| 2611 | outop(O_ROTATE); |
| 2612 | } |
| 2613 | |
| 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); |
| 2625 | outop(O_TRANSLATE); |
| 2626 | outint(90); |
| 2627 | outop(O_ROTATE); |
| 2628 | } |
| 2629 | setscale(); |
| 2630 | |
| 2631 | /* make sure things are reset to default values */ |
| 2632 | Last_linetype = -1; |
| 2633 | Doing_dotted = NO; |
| 2634 | Curr_font = FONT_UNKNOWN; |
| 2635 | Curr_size = DFLT_SIZE; |
| 2636 | } |
| 2637 | } |
| 2638 | \f |
| 2639 | |
| 2640 | /* print everything in list of PRINTDATAs, relative to specified offsets */ |
| 2641 | |
| 2642 | static void |
| 2643 | pr_print(printdata_p) |
| 2644 | |
| 2645 | struct PRINTDATA *printdata_p; /* list of things to print */ |
| 2646 | |
| 2647 | { |
| 2648 | float x, y; /* coordinate */ |
| 2649 | struct COORD_INFO *coordinfo_p; /* to find out if coord is associated |
| 2650 | * with something that is invisible */ |
| 2651 | |
| 2652 | |
| 2653 | /* walk down list of things to print */ |
| 2654 | for ( ; printdata_p != (struct PRINTDATA *) 0; |
| 2655 | printdata_p = printdata_p->next) { |
| 2656 | |
| 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) { |
| 2662 | continue; |
| 2663 | } |
| 2664 | } |
| 2665 | if ( (coordinfo_p = find_coord(printdata_p->location.vert_p)) |
| 2666 | != (struct COORD_INFO *) 0) { |
| 2667 | if (coordinfo_p->flags & CT_INVISIBLE) { |
| 2668 | continue; |
| 2669 | } |
| 2670 | } |
| 2671 | |
| 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 ); |
| 2677 | |
| 2678 | /* justify as specified */ |
| 2679 | switch (printdata_p->justifytype) { |
| 2680 | |
| 2681 | case J_RIGHT: |
| 2682 | x -= printdata_p->width; |
| 2683 | break; |
| 2684 | |
| 2685 | case J_CENTER: |
| 2686 | x -= printdata_p->width / 2.0; |
| 2687 | break; |
| 2688 | |
| 2689 | default: |
| 2690 | break; |
| 2691 | } |
| 2692 | |
| 2693 | if (printdata_p->isPostScript) { |
| 2694 | outop(O_SAVE); |
| 2695 | do_moveto(x, y); |
| 2696 | printf("%s\n", printdata_p->string + 2); |
| 2697 | outop(O_RESTORE); |
| 2698 | do_moveto(x, y); |
| 2699 | continue; |
| 2700 | } |
| 2701 | |
| 2702 | /* print the string at proper place */ |
| 2703 | pr_wstring(x, y, printdata_p->string, printdata_p->justifytype, |
| 2704 | printdata_p->width, |
| 2705 | printdata_p->inputfile, |
| 2706 | printdata_p->inputlineno); |
| 2707 | } |
| 2708 | } |
| 2709 | \f |
| 2710 | |
| 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. |
| 2717 | */ |
| 2718 | |
| 2719 | double |
| 2720 | pr_clefsig(mll_p, clefsig_p, really_print) |
| 2721 | |
| 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 */ |
| 2726 | |
| 2727 | { |
| 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 |
| 2735 | * the bar line */ |
| 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 */ |
| 2743 | |
| 2744 | |
| 2745 | |
| 2746 | if ((Score_location_p == (float *) 0) && (really_print == YES) ) { |
| 2747 | pfatal("can't do clef/key/time: no feed"); |
| 2748 | } |
| 2749 | |
| 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 */ |
| 2753 | |
| 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) { |
| 2757 | return(0.0); |
| 2758 | } |
| 2759 | |
| 2760 | /* init bar_width for now; if needed we will calculate a |
| 2761 | * value below */ |
| 2762 | bar_width = 0.0; |
| 2763 | |
| 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); |
| 2772 | break; |
| 2773 | } |
| 2774 | } |
| 2775 | } |
| 2776 | |
| 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++) { |
| 2783 | |
| 2784 | /* if staff is invisible, nothing to do */ |
| 2785 | if ( (svpath(s, VISIBLE))->visible == NO) { |
| 2786 | continue; |
| 2787 | } |
| 2788 | |
| 2789 | if ((stscale = svpath(s, STAFFSCALE)->staffscale) |
| 2790 | > biggest_stscale) { |
| 2791 | biggest_stscale = stscale; |
| 2792 | } |
| 2793 | |
| 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 */ |
| 2803 | continue; |
| 2804 | } |
| 2805 | |
| 2806 | /* if no clef is to be printed, don't print one */ |
| 2807 | if ( (svpath(s, STAFFLINES))->printclef == SS_NOTHING) { |
| 2808 | continue; |
| 2809 | } |
| 2810 | |
| 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... |
| 2821 | */ |
| 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; |
| 2827 | m_p = m_p->next) { |
| 2828 | if (m_p->str == S_SSV) { |
| 2829 | asgnssv(m_p->u.ssv_p); |
| 2830 | looked_ahead = YES; |
| 2831 | } |
| 2832 | else { |
| 2833 | break; |
| 2834 | } |
| 2835 | } |
| 2836 | } |
| 2837 | /* print clef if necessary */ |
| 2838 | if (clefsig_p->prclef[s] == YES) { |
| 2839 | set_staffscale(s); |
| 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 - |
| 2846 | Staffscale * |
| 2847 | width(FONT_MUSIC, clefsize, |
| 2848 | clefchar(svpath(s, CLEF)->clef))); |
| 2849 | } |
| 2850 | else { |
| 2851 | clefsize = DFLT_SIZE; |
| 2852 | clefx = clefsig_p->wclefsiga; |
| 2853 | } |
| 2854 | itemwidth = pr_clef(s, clefx, really_print, clefsize); |
| 2855 | if (itemwidth > maxclefwidth) { |
| 2856 | maxclefwidth = itemwidth; |
| 2857 | } |
| 2858 | } |
| 2859 | } |
| 2860 | |
| 2861 | /* allow a little space before key/time signature */ |
| 2862 | if (maxclefwidth > 0.0 && clefsig_p->clefsize != SMALLSIZE) { |
| 2863 | maxclefwidth += CLEFPAD * biggest_stscale; |
| 2864 | } |
| 2865 | |
| 2866 | /* print key sig if necessary */ |
| 2867 | for (s = 1, maxkswidth = 0.0; s <= MAXSTAFFS; s++) { |
| 2868 | |
| 2869 | /* if staff is invisible, nothing to do */ |
| 2870 | if ( (svpath(s, VISIBLE))->visible == NO) { |
| 2871 | continue; |
| 2872 | } |
| 2873 | |
| 2874 | /* if no clef is to be printed, don't print key sig either */ |
| 2875 | if ( (svpath(s, STAFFLINES))->printclef != SS_NORMAL) { |
| 2876 | continue; |
| 2877 | } |
| 2878 | |
| 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 */ |
| 2884 | continue; |
| 2885 | } |
| 2886 | |
| 2887 | if (clefsig_p->sharps[s] != 0 || clefsig_p->naturals[s] != 0) { |
| 2888 | set_staffscale(s); |
| 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; |
| 2895 | } |
| 2896 | } |
| 2897 | } |
| 2898 | /* If there was a keysig, add some padding after it */ |
| 2899 | if (maxkswidth > 0.0) { |
| 2900 | maxkswidth += 2.0 * STDPAD * biggest_stscale; |
| 2901 | } |
| 2902 | |
| 2903 | total_width = maxclefwidth + maxkswidth; |
| 2904 | |
| 2905 | /* print time sig if necessary */ |
| 2906 | tsigwidth = 0.0; |
| 2907 | if (clefsig_p->prtimesig == YES) { |
| 2908 | |
| 2909 | for (s = 1; s <= MAXSTAFFS; s++) { |
| 2910 | |
| 2911 | /* if staff is invisible, nothing to do */ |
| 2912 | if ( (svpath(s, VISIBLE))->visible == NO) { |
| 2913 | continue; |
| 2914 | } |
| 2915 | |
| 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 |
| 2922 | * of the page */ |
| 2923 | continue; |
| 2924 | } |
| 2925 | |
| 2926 | set_staffscale(s); |
| 2927 | curr_tsigwidth = pr_timesig(s, |
| 2928 | (double) (clefsig_p->wclefsiga + bar_width + |
| 2929 | + total_width), clefsig_p->multinum, |
| 2930 | really_print); |
| 2931 | |
| 2932 | /* if widest time signature found so far, |
| 2933 | * save its width */ |
| 2934 | if (curr_tsigwidth > tsigwidth) { |
| 2935 | tsigwidth = curr_tsigwidth; |
| 2936 | } |
| 2937 | } |
| 2938 | |
| 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); |
| 2943 | } |
| 2944 | } |
| 2945 | |
| 2946 | /* do pseudo-bar things */ |
| 2947 | if (clefsig_p->bar_p != (struct BAR *) 0) { |
| 2948 | |
| 2949 | if (clefsig_p->bar_p->bartype != INVISBAR) { |
| 2950 | |
| 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 |
| 2955 | )), YES); |
| 2956 | } |
| 2957 | total_width += width_barline(clefsig_p->bar_p); |
| 2958 | } |
| 2959 | if (really_print == YES) { |
| 2960 | /* save pedal info needed to deal with endings */ |
| 2961 | saveped(mll_p, clefsig_p->bar_p); |
| 2962 | } |
| 2963 | } |
| 2964 | |
| 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. |
| 2971 | */ |
| 2972 | setssvstate(mll_p); |
| 2973 | } |
| 2974 | |
| 2975 | return(total_width); |
| 2976 | } |
| 2977 | \f |
| 2978 | |
| 2979 | /* print a clef on specified staff */ |
| 2980 | /* return the width of what was printed */ |
| 2981 | |
| 2982 | double |
| 2983 | pr_clef(staffno, x, really_print, size) |
| 2984 | |
| 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 */ |
| 2989 | |
| 2990 | { |
| 2991 | char muschar; /* clef character */ |
| 2992 | float y_offset; /* where to place clef vertical relative to staff */ |
| 2993 | int clef; |
| 2994 | float y; |
| 2995 | |
| 2996 | |
| 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); |
| 3008 | } |
| 3009 | return (5.0 * Stepsize); |
| 3010 | } |
| 3011 | |
| 3012 | /* figure out which clef to use */ |
| 3013 | clef = svpath(staffno, CLEF)->clef; |
| 3014 | muschar = clefchar(clef); |
| 3015 | |
| 3016 | /* figure out vertical placement */ |
| 3017 | if (clef == TABCLEF) { |
| 3018 | return(pr_tabclef(staffno, x, really_print, size)); |
| 3019 | } |
| 3020 | |
| 3021 | y_offset = clefvert(clef, NO, 0, 0) * STEPSIZE; |
| 3022 | |
| 3023 | /* print the clef */ |
| 3024 | if (really_print) { |
| 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) { |
| 3031 | double y8; |
| 3032 | char tr8str[4]; |
| 3033 | |
| 3034 | tr8str[0] = FONT_TI; |
| 3035 | /* 9-point, but adjusted by staffscale */ |
| 3036 | tr8str[1] = (char) adj_size(9, Staffscale, |
| 3037 | (char *) 0, -1); |
| 3038 | tr8str[2] = '8'; |
| 3039 | tr8str[3] = '\0'; |
| 3040 | if (clef == TREBLE_8) { |
| 3041 | y8 = y - descent(FONT_MUSIC, size, muschar) |
| 3042 | * Staffscale |
| 3043 | - strascent(tr8str) + (2.0 * Stdpad); |
| 3044 | } |
| 3045 | else { |
| 3046 | y8 = y + ascent(FONT_MUSIC, size, muschar) |
| 3047 | * Staffscale - Stdpad; |
| 3048 | } |
| 3049 | j_outstring(x, y8, tr8str, J_CENTER, strwidth(tr8str), |
| 3050 | (char *) 0, -1); |
| 3051 | } |
| 3052 | pr_muschar(x, y, muschar, size, FONT_MUSIC); |
| 3053 | } |
| 3054 | |
| 3055 | return (width(FONT_MUSIC, size, muschar) + CLEFPAD) * Staffscale; |
| 3056 | } |
| 3057 | \f |
| 3058 | |
| 3059 | /* print key signature on specified staff */ |
| 3060 | /* return the width of what was printed */ |
| 3061 | |
| 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 */ |
| 3064 | |
| 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 }; |
| 3069 | |
| 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 }; |
| 3075 | |
| 3076 | |
| 3077 | static double |
| 3078 | pr_keysig(staffno, sharps, naturals, x, really_print) |
| 3079 | |
| 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 */ |
| 3085 | |
| 3086 | { |
| 3087 | float y; /* vertical location */ |
| 3088 | int *sharptbl, *flattbl; /* table of physical offsets */ |
| 3089 | int offset; /* to compensate for clef */ |
| 3090 | |
| 3091 | |
| 3092 | if (sharps == 0 && naturals == 0) { |
| 3093 | return(0.0); |
| 3094 | } |
| 3095 | |
| 3096 | /* if just getting width, just calculate that */ |
| 3097 | if (really_print == NO) { |
| 3098 | return(width_keysig(sharps, naturals)); |
| 3099 | } |
| 3100 | |
| 3101 | y = Staffs_y[staffno]; |
| 3102 | |
| 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; |
| 3108 | |
| 3109 | switch ( (svpath(staffno, CLEF))->clef ) { |
| 3110 | |
| 3111 | case TREBLE: |
| 3112 | case TREBLE_8: |
| 3113 | case TREBLE_8A: |
| 3114 | offset = 0; |
| 3115 | break; |
| 3116 | |
| 3117 | case FRENCHVIOLIN: |
| 3118 | case BASS: |
| 3119 | offset = -2; |
| 3120 | break; |
| 3121 | |
| 3122 | case SOPRANO: |
| 3123 | if ( sharps > 0) { |
| 3124 | sharptbl = Alt2_sharps_pattern; |
| 3125 | offset = -1; |
| 3126 | } |
| 3127 | else { |
| 3128 | flattbl = Alt_flats_pattern; |
| 3129 | offset = -2; |
| 3130 | } |
| 3131 | break; |
| 3132 | |
| 3133 | case MEZZOSOPRANO: |
| 3134 | if (sharps < 0) { |
| 3135 | flattbl = Alt_flats_pattern; |
| 3136 | offset = 0; |
| 3137 | } |
| 3138 | else { |
| 3139 | offset = -3; |
| 3140 | } |
| 3141 | break; |
| 3142 | |
| 3143 | case ALTO: |
| 3144 | offset = -1; |
| 3145 | break; |
| 3146 | |
| 3147 | case TENOR: |
| 3148 | if (sharps > 0) { |
| 3149 | sharptbl = Alt_sharps_pattern; |
| 3150 | offset = -1; |
| 3151 | } |
| 3152 | else { |
| 3153 | offset = 1; |
| 3154 | } |
| 3155 | break; |
| 3156 | |
| 3157 | case BARITONE: |
| 3158 | if (sharps < 0) { |
| 3159 | flattbl = Alt_flats_pattern; |
| 3160 | offset = -1; |
| 3161 | } |
| 3162 | else { |
| 3163 | sharptbl = Alt2_sharps_pattern; |
| 3164 | offset = 0; |
| 3165 | } |
| 3166 | break; |
| 3167 | |
| 3168 | case TABCLEF: |
| 3169 | return(0.0); |
| 3170 | |
| 3171 | default: |
| 3172 | pfatal("unknown clef"); |
| 3173 | /*NOTREACHED*/ |
| 3174 | offset = 0; /* to shut up bogus compiler warning */ |
| 3175 | break; |
| 3176 | } |
| 3177 | |
| 3178 | set_cur(x, y); |
| 3179 | /* cancel a previous key signature of flats */ |
| 3180 | if (naturals < 0) { |
| 3181 | draw_keysig(C_NAT, - naturals, (double) x, (double) y, |
| 3182 | flattbl, offset, (sharps < 0 ? -sharps : 0)); |
| 3183 | } |
| 3184 | |
| 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)); |
| 3189 | } |
| 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); |
| 3193 | } |
| 3194 | |
| 3195 | /* do key signatures with sharps */ |
| 3196 | if (sharps > 0) { |
| 3197 | draw_keysig(C_SHARP, sharps, (double) _Cur[AX], (double) y, |
| 3198 | sharptbl, offset, 0); |
| 3199 | } |
| 3200 | |
| 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); |
| 3205 | } |
| 3206 | |
| 3207 | /* return the width of what we printed */ |
| 3208 | return( _Cur[AX] - x); |
| 3209 | } |
| 3210 | \f |
| 3211 | |
| 3212 | /* actually draw a key signature, given all the info about what and where |
| 3213 | * to do it */ |
| 3214 | |
| 3215 | static void |
| 3216 | draw_keysig(muschar, symbols, x, y, table, offset, skip) |
| 3217 | |
| 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) */ |
| 3225 | |
| 3226 | { |
| 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) */ |
| 3232 | |
| 3233 | |
| 3234 | _Cur[AX] = x; |
| 3235 | |
| 3236 | /* have to compensate for music char's x being in its middle */ |
| 3237 | compensation = width(FONT_MUSIC, DFLT_SIZE, muschar) * Staffscale / 2.0; |
| 3238 | |
| 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); |
| 3247 | } |
| 3248 | } |
| 3249 | \f |
| 3250 | |
| 3251 | /* print time signature on specified staff */ |
| 3252 | /* return width of what was printed */ |
| 3253 | |
| 3254 | static double |
| 3255 | pr_timesig(staffno, x, multnum, really_print) |
| 3256 | |
| 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 */ |
| 3261 | |
| 3262 | { |
| 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 */ |
| 3273 | |
| 3274 | |
| 3275 | if (is_tab_staff(staffno) == YES) { |
| 3276 | /* tab staffs never have a time signature */ |
| 3277 | return(0.0); |
| 3278 | } |
| 3279 | |
| 3280 | if ( Score.timevis == PTS_NEVER ) { |
| 3281 | /* not visible */ |
| 3282 | return(0.0); |
| 3283 | } |
| 3284 | |
| 3285 | numwidth = denwidth = thiswidth = totalwidth = numjam = denjam = 0.0; |
| 3286 | |
| 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); |
| 3290 | numstr[2] = '\0'; |
| 3291 | plusstr[2] = '+'; |
| 3292 | plusstr[3] = '\0'; |
| 3293 | |
| 3294 | for (t = Score.timerep; *t != TSR_END; t++) { |
| 3295 | |
| 3296 | if (*t == TSR_CUT || *t == TSR_COMMON) { |
| 3297 | char tschar; |
| 3298 | |
| 3299 | tschar = (*t == TSR_CUT ? C_CUT : C_COM); |
| 3300 | thiswidth = width(FONT_MUSIC, DFLT_SIZE, tschar) * Staffscale; |
| 3301 | totalwidth += thiswidth; |
| 3302 | if (really_print) { |
| 3303 | pr_muschar( x + totalwidth - (thiswidth / 2.0), |
| 3304 | Staffs_y[staffno], tschar, |
| 3305 | DFLT_SIZE, FONT_MUSIC); |
| 3306 | } |
| 3307 | } |
| 3308 | |
| 3309 | else if (*t == TSR_SLASH) { |
| 3310 | t++; |
| 3311 | (void) sprintf(denstr + 2, "%d", *t); |
| 3312 | denjam = tsjam(*t); |
| 3313 | denwidth = strwidth(denstr) - denjam; |
| 3314 | numwidth = strwidth(numstr) - numjam; |
| 3315 | thiswidth = MAX(numwidth, denwidth); |
| 3316 | if (really_print) { |
| 3317 | double xx; |
| 3318 | char onenum[8]; /* one component of numerator */ |
| 3319 | int n; /* index into numstr */ |
| 3320 | |
| 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++) { |
| 3328 | |
| 3329 | if (numstr[n] == '+') { |
| 3330 | pr_string(xx, y + 2.0 * Stdpad, |
| 3331 | plusstr, J_LEFT, |
| 3332 | (char *) 0, -1); |
| 3333 | xx = _Cur[AX]; |
| 3334 | continue; |
| 3335 | } |
| 3336 | |
| 3337 | onenum[2] = numstr[n]; |
| 3338 | if (isdigit(numstr[n+1])) { |
| 3339 | onenum[3] = numstr[++n]; |
| 3340 | onenum[4] = '\0'; |
| 3341 | } |
| 3342 | else { |
| 3343 | onenum[3] = '\0'; |
| 3344 | } |
| 3345 | pr_tsnum(xx, y, onenum, tsjam(atoi(onenum + 2))); |
| 3346 | xx = _Cur[AX]; |
| 3347 | } |
| 3348 | |
| 3349 | /* print denominator */ |
| 3350 | y = Staffs_y[staffno] - strheight(denstr) |
| 3351 | + (2.0 * Stdpad); |
| 3352 | pr_tsnum(x + totalwidth + |
| 3353 | (thiswidth - denwidth)/2.0, y, |
| 3354 | denstr, denjam); |
| 3355 | |
| 3356 | } |
| 3357 | totalwidth += thiswidth; |
| 3358 | |
| 3359 | /* Reset things in case there is another |
| 3360 | * time signature component */ |
| 3361 | numwidth = denwidth = 0.0; |
| 3362 | numstr[2] = denstr[2] = '\0'; |
| 3363 | numjam = 0.0; |
| 3364 | } |
| 3365 | |
| 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) { |
| 3376 | break; |
| 3377 | } |
| 3378 | } |
| 3379 | |
| 3380 | /* add some space */ |
| 3381 | /* reuse the numstr */ |
| 3382 | numstr[2] = ' '; |
| 3383 | numstr[3] = '\0'; |
| 3384 | numwidth = strwidth(numstr); |
| 3385 | if (really_print) { |
| 3386 | pr_string(x + totalwidth, |
| 3387 | Staffs_y[staffno] - strheight(numstr)/2.0, |
| 3388 | numstr, J_LEFT, (char *) 0, -1); |
| 3389 | } |
| 3390 | totalwidth += numwidth; |
| 3391 | /* reset for the next numerator */ |
| 3392 | numstr[2] = '\0'; |
| 3393 | numwidth = 0.0; |
| 3394 | } |
| 3395 | |
| 3396 | else if (*t == TSR_ADD) { |
| 3397 | if (really_print) { |
| 3398 | pr_string(x + totalwidth, |
| 3399 | Staffs_y[staffno] |
| 3400 | - strheight(plusstr)/2.0 + 1.5 * Stdpad, |
| 3401 | plusstr, J_LEFT, (char *) 0, -1); |
| 3402 | } |
| 3403 | totalwidth += strwidth(plusstr); |
| 3404 | } |
| 3405 | |
| 3406 | else { |
| 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, "+"); |
| 3411 | } |
| 3412 | (void) sprintf(numstr + strlen(numstr), "%d", *t); |
| 3413 | numjam += tsjam(*t); |
| 3414 | } |
| 3415 | } |
| 3416 | |
| 3417 | return (totalwidth); |
| 3418 | } |
| 3419 | \f |
| 3420 | |
| 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 |
| 3423 | * need jamming). |
| 3424 | */ |
| 3425 | |
| 3426 | static double |
| 3427 | tsjam(num) |
| 3428 | |
| 3429 | int num; |
| 3430 | |
| 3431 | { |
| 3432 | /* jam numbers 10 and 13-19 together a bit */ |
| 3433 | return ( (num == 10 || (num > 12 && num < 20)) ? 2.0 * Stdpad : 0.0); |
| 3434 | } |
| 3435 | \f |
| 3436 | |
| 3437 | |
| 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. |
| 3442 | */ |
| 3443 | |
| 3444 | static void |
| 3445 | pr_tsnum(x, y, str, jam) |
| 3446 | |
| 3447 | double x; |
| 3448 | double y; |
| 3449 | char *str; |
| 3450 | double jam; |
| 3451 | |
| 3452 | { |
| 3453 | char save; |
| 3454 | |
| 3455 | if (jam > 0.0) { |
| 3456 | /* split and print 1 digit at a time */ |
| 3457 | save = str[3]; |
| 3458 | str[3] = '\0'; |
| 3459 | pr_string(x, y, str, J_LEFT, (char *) 0, -1); |
| 3460 | str[2] = save; |
| 3461 | pr_string(_Cur[AX] - jam, y, str, J_LEFT, (char *) 0, -1); |
| 3462 | } |
| 3463 | else { |
| 3464 | pr_string(x, y, str, J_LEFT, (char *) 0, -1); |
| 3465 | } |
| 3466 | } |
| 3467 | \f |
| 3468 | |
| 3469 | /* print a string */ |
| 3470 | |
| 3471 | void |
| 3472 | pr_string(x, y, string, justify, fname, lineno) |
| 3473 | |
| 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 */ |
| 3479 | |
| 3480 | { |
| 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); |
| 3485 | } |
| 3486 | |
| 3487 | /* more general string printing function that handles right justified paragraphs */ |
| 3488 | |
| 3489 | static void |
| 3490 | pr_wstring(x, y, string, justify, fullwidth, fname, lineno) |
| 3491 | |
| 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 */ |
| 3498 | |
| 3499 | { |
| 3500 | /* skip any empty strings */ |
| 3501 | if ( ( string == (char *) 0) || (*string == '\0') ) { |
| 3502 | return; |
| 3503 | } |
| 3504 | |
| 3505 | /* set font and size */ |
| 3506 | pr_font( (int) string[0], (int) string[1]); |
| 3507 | |
| 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)); |
| 3516 | |
| 3517 | |
| 3518 | x += 3.5 * STDPAD; |
| 3519 | } |
| 3520 | if (IS_CIRCLED(string) == YES) { |
| 3521 | float circ_height; |
| 3522 | float circ_width; |
| 3523 | float elongation_factor; |
| 3524 | float x_offset; |
| 3525 | float radius; |
| 3526 | float x_center, y_center; |
| 3527 | |
| 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; |
| 3533 | |
| 3534 | /* we will fiddle with the transform matrix so do inside |
| 3535 | * save/restore */ |
| 3536 | outop(O_GSAVE); |
| 3537 | outop(O_NEWPATH); |
| 3538 | |
| 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); |
| 3544 | |
| 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); |
| 3550 | |
| 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); |
| 3554 | |
| 3555 | /* fill in the area between the inner and outer elipses */ |
| 3556 | outop(O_EOFILL); |
| 3557 | outop(O_GRESTORE); |
| 3558 | |
| 3559 | /* adjust x for where text should be printed */ |
| 3560 | x += x_offset; |
| 3561 | } |
| 3562 | |
| 3563 | split_a_string(x, y, string, justify, fullwidth, fname, lineno); |
| 3564 | } |
| 3565 | \f |
| 3566 | |
| 3567 | /* Draw a circle (or maybe elipse, if scaling is in effect) */ |
| 3568 | |
| 3569 | static void |
| 3570 | draw_circle(x, y, radius) |
| 3571 | |
| 3572 | double x, y; /* of circle center */ |
| 3573 | double radius; |
| 3574 | |
| 3575 | { |
| 3576 | outcoord(x); |
| 3577 | outcoord(y); |
| 3578 | outcoord(radius); |
| 3579 | outint(0); |
| 3580 | outint(360); |
| 3581 | outop(O_ARC); |
| 3582 | } |
| 3583 | \f |
| 3584 | |
| 3585 | /* output instructions for setting font and size */ |
| 3586 | |
| 3587 | static void |
| 3588 | pr_font(font, size) |
| 3589 | |
| 3590 | int font; |
| 3591 | int size; |
| 3592 | |
| 3593 | { |
| 3594 | #ifdef SMALLMEMORY |
| 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) { |
| 3598 | outop(O_RESTORE); |
| 3599 | } |
| 3600 | outop(O_SAVE); |
| 3601 | Did_save = YES; |
| 3602 | #endif |
| 3603 | |
| 3604 | Curr_font = font; |
| 3605 | Curr_size = size; |
| 3606 | |
| 3607 | prfontname(font); |
| 3608 | |
| 3609 | outop(O_FONT); |
| 3610 | |
| 3611 | outint(size); |
| 3612 | outop(O_SIZE); |
| 3613 | outop(O_SETFONT); |
| 3614 | |
| 3615 | Font_used[font] = YES; |
| 3616 | } |
| 3617 | \f |
| 3618 | |
| 3619 | /* print font name */ |
| 3620 | |
| 3621 | static void |
| 3622 | prfontname(font) |
| 3623 | |
| 3624 | int font; |
| 3625 | { |
| 3626 | OUTP(("/%s ", Fontinfo[font_index(font)].ps_name)); |
| 3627 | } |
| 3628 | \f |
| 3629 | |
| 3630 | /* split a string into lines and print each line */ |
| 3631 | |
| 3632 | static void |
| 3633 | split_a_string(x, y, string, justify, fullwidth, fname, lineno) |
| 3634 | |
| 3635 | double x; /* coordinate at which to print string */ |
| 3636 | double y; |
| 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 */ |
| 3643 | |
| 3644 | { |
| 3645 | int font, size; /* current font and size */ |
| 3646 | int origfont, origsize; /* font & size at beginning of current line |
| 3647 | * of text */ |
| 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 */ |
| 3652 | |
| 3653 | |
| 3654 | origfont = font = string[0]; |
| 3655 | origsize = size = string[1]; |
| 3656 | text = string + 2; |
| 3657 | |
| 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); |
| 3662 | } |
| 3663 | |
| 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). */ |
| 3668 | text++; |
| 3669 | fullwidth -= 7.0 * STDPAD; |
| 3670 | } |
| 3671 | p = text; |
| 3672 | MALLOCA(char, buff, strlen(string) + 1); |
| 3673 | do { |
| 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') { |
| 3686 | justify = J_LEFT; |
| 3687 | } |
| 3688 | |
| 3689 | j_outstring(x, y, buff, justify, fullwidth, |
| 3690 | fname, lineno); |
| 3691 | |
| 3692 | /* prepare for next line, if any */ |
| 3693 | origfont = font; |
| 3694 | origsize = size; |
| 3695 | text = p; |
| 3696 | y -= fontheight(font, size); |
| 3697 | } |
| 3698 | } while (c != '\0'); |
| 3699 | FREE(buff); |
| 3700 | } |
| 3701 | \f |
| 3702 | |
| 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) */ |
| 3707 | |
| 3708 | static void |
| 3709 | j_outstring(x, y, string, justify, fullwidth, fname, lineno) |
| 3710 | |
| 3711 | double x; |
| 3712 | double y; |
| 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 */ |
| 3718 | |
| 3719 | { |
| 3720 | switch (justify) { |
| 3721 | case J_NONE: |
| 3722 | /* NONE is effectively the same as LEFT */ |
| 3723 | /*FALLTHRU*/ |
| 3724 | case J_LEFT: |
| 3725 | case J_RAGPARA: |
| 3726 | outstring(x, y, -1.0, string, fname, lineno); |
| 3727 | break; |
| 3728 | case J_JUSTPARA: |
| 3729 | outstring(x, y, fullwidth, string, fname, lineno); |
| 3730 | break; |
| 3731 | case J_CENTER: |
| 3732 | outstring(x + (fullwidth - strwidth(string)) / 2.0, y, |
| 3733 | -1.0, string, fname, lineno); |
| 3734 | break; |
| 3735 | case J_RIGHT: |
| 3736 | outstring(x + fullwidth - strwidth(string), y, -1.0, |
| 3737 | string, fname, lineno); |
| 3738 | break; |
| 3739 | default: |
| 3740 | pfatal("bad justification type"); |
| 3741 | /*NOTREACHED*/ |
| 3742 | break; |
| 3743 | } |
| 3744 | } |
| 3745 | \f |
| 3746 | |
| 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 */ |
| 3749 | |
| 3750 | static void |
| 3751 | set_staff_y(main_p) |
| 3752 | |
| 3753 | struct MAINLL *main_p; |
| 3754 | |
| 3755 | { |
| 3756 | int s; |
| 3757 | |
| 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++) { |
| 3764 | Staffs_y[s] = 0.0; |
| 3765 | } |
| 3766 | |
| 3767 | for ( ; main_p != (struct MAINLL *) 0; main_p = main_p->next) { |
| 3768 | |
| 3769 | if (main_p->str == S_BAR) { |
| 3770 | /* reached end of list of staffs in this measure */ |
| 3771 | return; |
| 3772 | } |
| 3773 | |
| 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]; |
| 3778 | } |
| 3779 | } |
| 3780 | } |
| 3781 | \f |
| 3782 | |
| 3783 | /* print measure number at beginning of score if user wants them */ |
| 3784 | |
| 3785 | static void |
| 3786 | pr_meas_num(staffno, x) |
| 3787 | |
| 3788 | int staffno; /* which staff to possible put measure number on */ |
| 3789 | double x; /* where to put measure number */ |
| 3790 | |
| 3791 | { |
| 3792 | float y_adj; /* to avoid clefs */ |
| 3793 | int clef; |
| 3794 | |
| 3795 | |
| 3796 | /* measure numbers only put on those staffs that have endings */ |
| 3797 | if (has_ending(staffno) ) { |
| 3798 | |
| 3799 | /* print measure number if user wants them */ |
| 3800 | if ( (svpath(staffno, MEASNUM)->measnum == YES) |
| 3801 | && (Meas_num > 1)) { |
| 3802 | |
| 3803 | /* construct the measure number string */ |
| 3804 | char mnumstr[8]; |
| 3805 | mnumstr[0] = (char) (Score.measnumfamily |
| 3806 | + Score.measnumfont); |
| 3807 | mnumstr[1] = (char) Score.measnumsize; |
| 3808 | (void) sprintf(mnumstr + 2, "%d", Meas_num); |
| 3809 | |
| 3810 | /* print it */ |
| 3811 | if (is_tab_staff(staffno) == YES) { |
| 3812 | clef = TABCLEF; |
| 3813 | } |
| 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) { |
| 3817 | clef = NOCLEF; |
| 3818 | } |
| 3819 | else { |
| 3820 | clef = svpath(staffno, CLEF)->clef; |
| 3821 | } |
| 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); |
| 3835 | } |
| 3836 | } |
| 3837 | } |
| 3838 | \f |
| 3839 | |
| 3840 | /* tell PostScript about file and linenumber */ |
| 3841 | |
| 3842 | void |
| 3843 | pr_linenum (inputfile, inputlineno) |
| 3844 | |
| 3845 | char *inputfile; |
| 3846 | int inputlineno; |
| 3847 | |
| 3848 | { |
| 3849 | static char *fname = ""; /* keep track of current file |
| 3850 | * name to only output it when |
| 3851 | * it changes */ |
| 3852 | char *str; /* walk thru file name to |
| 3853 | * add backslashes if needed */ |
| 3854 | |
| 3855 | |
| 3856 | if (strcmp(fname, inputfile) != 0) { |
| 3857 | OUTPCH(('(')); |
| 3858 | for (str = inputfile; *str != 0; str++) { |
| 3859 | switch(*str) { |
| 3860 | case '\\': |
| 3861 | case '(': |
| 3862 | case ')': |
| 3863 | OUTPCH(('\\')); |
| 3864 | /*FALLTHRU*/ |
| 3865 | default: |
| 3866 | OUTPCH((*str)); |
| 3867 | break; |
| 3868 | } |
| 3869 | } |
| 3870 | OUTP((") inputfile\n")); |
| 3871 | fname = inputfile; |
| 3872 | } |
| 3873 | OUTP(("%d linenum\n", inputlineno)); |
| 3874 | } |
| 3875 | \f |
| 3876 | |
| 3877 | /* output the current scale factor */ |
| 3878 | |
| 3879 | static void |
| 3880 | setscale() |
| 3881 | |
| 3882 | { |
| 3883 | OUTP(("%f %f scale\n", Score.scale_factor, Score.scale_factor)); |
| 3884 | } |
| 3885 | \f |
| 3886 | |
| 3887 | /* For debugging, this generates PostScript to draw colored bounding boxes |
| 3888 | * representing coordinates (the 13-element arrays called "c" |
| 3889 | * in various structs). |
| 3890 | */ |
| 3891 | |
| 3892 | static void |
| 3893 | show_coord(coord_p, index) |
| 3894 | |
| 3895 | float *coord_p; /* which one to draw */ |
| 3896 | int index; /* index into Bbox_list, to get colors to use */ |
| 3897 | |
| 3898 | { |
| 3899 | struct Bbox *bb_p; |
| 3900 | |
| 3901 | bb_p = &(Bbox_list[index]); |
| 3902 | outop(O_GSAVE); |
| 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)); |
| 3909 | } |
| 3910 | pr_box(coord_p[AW], coord_p[AS], coord_p[AN] - coord_p[AS], coord_p[AE] - coord_p[AW]); |
| 3911 | outop(O_GRESTORE); |
| 3912 | } |
| 3913 | \f |
| 3914 | |
| 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. |
| 3920 | */ |
| 3921 | |
| 3922 | static void |
| 3923 | prep_bbox() |
| 3924 | { |
| 3925 | char *bb; |
| 3926 | int i; |
| 3927 | |
| 3928 | if ((bb = getenv("MUP_BB")) == 0) { |
| 3929 | /* user doesn't want bounding box debugging */ |
| 3930 | return; |
| 3931 | } |
| 3932 | |
| 3933 | /* If a coordinate type's id is set in MUP_BB, set its corresponding |
| 3934 | * flag bit */ |
| 3935 | for (i = 0; i < NUMELEM(Bbox_list); i++) { |
| 3936 | if (strchr(bb, Bbox_list[i].id) != 0) { |
| 3937 | BB_SET(i); |
| 3938 | } |
| 3939 | } |
| 3940 | } |
| 3941 | \f |
| 3942 | |
| 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. |
| 3952 | */ |
| 3953 | |
| 3954 | static void |
| 3955 | show_bounding_boxes(mll_p) |
| 3956 | |
| 3957 | struct MAINLL *mll_p; /* FEED for end of current page, or could be |
| 3958 | * Mainlltc_p if at end of song. */ |
| 3959 | |
| 3960 | { |
| 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; |
| 3966 | |
| 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) { |
| 3970 | /* Skip this feed. |
| 3971 | * We want to back up to previous page feed, if any */ |
| 3972 | mll_p = mll_p->prev; |
| 3973 | } |
| 3974 | |
| 3975 | for ( ; mll_p != 0; mll_p = mll_p->prev) { |
| 3976 | switch (mll_p->str) { |
| 3977 | |
| 3978 | case S_BAR: |
| 3979 | if (BB_IS_SET(BB_BAR)) { |
| 3980 | show_coord(mll_p->u.bar_p->c, BB_BAR); |
| 3981 | } |
| 3982 | break; |
| 3983 | |
| 3984 | case S_FEED: |
| 3985 | if (BB_IS_SET(BB_FEED)) { |
| 3986 | show_coord(mll_p->u.feed_p->c, BB_FEED); |
| 3987 | } |
| 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); |
| 3995 | } |
| 3996 | else { |
| 3997 | show_coord(Header2.c, BB_BLOCKHEAD); |
| 3998 | show_coord(Footer2.c, BB_BLOCKHEAD); |
| 3999 | } |
| 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); |
| 4003 | set_win_coord(0); |
| 4004 | } |
| 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); |
| 4008 | set_win_coord(0); |
| 4009 | } |
| 4010 | } |
| 4011 | if (mll_p->u.feed_p->pagefeed == YES) { |
| 4012 | /* reached top of current page; we're done */ |
| 4013 | return; |
| 4014 | } |
| 4015 | } |
| 4016 | break; |
| 4017 | |
| 4018 | case S_STAFF: |
| 4019 | if (mll_p->u.staff_p->visible == NO) { |
| 4020 | break; |
| 4021 | } |
| 4022 | |
| 4023 | /* show the staff itself */ |
| 4024 | if (BB_IS_SET(BB_STAFF)) { |
| 4025 | show_coord(mll_p->u.staff_p->c, BB_STAFF); |
| 4026 | } |
| 4027 | |
| 4028 | /* Do groups and notes */ |
| 4029 | if (BB_IS_SET(BB_GRPSYL) || BB_IS_SET(BB_NOTE)) { |
| 4030 | for (v = 0; v < MAXVOICES; v++) { |
| 4031 | |
| 4032 | if (vvpath(mll_p->u.staff_p->staffno, |
| 4033 | v+1, VISIBLE)->visible |
| 4034 | == NO) { |
| 4035 | /* Skip invisible voices */ |
| 4036 | continue; |
| 4037 | } |
| 4038 | |
| 4039 | for (gs_p = mll_p->u.staff_p->groups_p[v]; |
| 4040 | gs_p != 0; |
| 4041 | gs_p = gs_p->next) { |
| 4042 | if (BB_IS_SET(BB_GRPSYL)) { |
| 4043 | show_coord(gs_p->c, BB_GRPSYL); |
| 4044 | } |
| 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); |
| 4049 | } |
| 4050 | } |
| 4051 | } |
| 4052 | } |
| 4053 | } |
| 4054 | |
| 4055 | /* now do lyrics */ |
| 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]; |
| 4059 | gs_p != 0; |
| 4060 | gs_p = gs_p->next) { |
| 4061 | show_coord(gs_p->c, BB_GRPSYL); |
| 4062 | } |
| 4063 | } |
| 4064 | } |
| 4065 | |
| 4066 | /* do the other "stuff" */ |
| 4067 | if (BB_IS_SET(BB_STUFF)) { |
| 4068 | for (stuff_p = mll_p->u.staff_p->stuff_p; |
| 4069 | stuff_p != 0; |
| 4070 | stuff_p = stuff_p->next) { |
| 4071 | show_coord(stuff_p->c, BB_STUFF); |
| 4072 | } |
| 4073 | } |
| 4074 | break; |
| 4075 | |
| 4076 | case S_CHHEAD: |
| 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); |
| 4081 | } |
| 4082 | } |
| 4083 | break; |
| 4084 | |
| 4085 | default: |
| 4086 | break; |
| 4087 | } |
| 4088 | } |
| 4089 | } |