Commit | Line | Data |
---|---|---|
69695f33 MW |
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 | } |