Commit | Line | Data |
---|---|---|
69695f33 MW |
1 | |
2 | /* Copyright (c) 1995, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006 by Arkkra Enterprises */ | |
3 | /* All rights reserved */ | |
4 | ||
5 | /* miscellaneous utility functions for music publication program, mostly | |
6 | * for the print phase */ | |
7 | ||
8 | #include "defines.h" | |
9 | #include "structs.h" | |
10 | #include "globals.h" | |
11 | ||
12 | static void grp_octave_adjust P((struct GRPSYL *gs_p, int adj, struct MAINLL *mll_p)); | |
13 | static void set_height_blockhead P((struct BLOCKHEAD *blockhead_p, int context, | |
14 | struct MAINLL *mll_p)); | |
15 | static double coord_staffscale P((float *coord_array)); | |
16 | ||
17 | \f | |
18 | ||
19 | /* set _cur location variable to specified value */ | |
20 | ||
21 | void | |
22 | set_cur(x, y) | |
23 | ||
24 | float x, y; /* x, east, and west get set to x value. y, north and south, | |
25 | * get set to y value */ | |
26 | ||
27 | { | |
28 | float *cur_p; /* coord array for _cur in current context */ | |
29 | ||
30 | ||
31 | /* look up _cur symbol and fill in the values */ | |
32 | cur_p = symval("_cur", (float **) 0); | |
33 | cur_p[AX] = cur_p[AE] = cur_p[AW] = x; | |
34 | cur_p[AY] = cur_p[AN] = cur_p[AS] = y; | |
35 | } | |
36 | \f | |
37 | ||
38 | /* set the values for location variable _win */ | |
39 | ||
40 | void | |
41 | set_win(n, s, e, w) | |
42 | ||
43 | float n, s, e, w; /* north, south, east, and west */ | |
44 | ||
45 | { | |
46 | float *window; /* coordinate info for _win */ | |
47 | ||
48 | ||
49 | /* look up symbol and fill in values */ | |
50 | window = symval("_win", (float **) 0); | |
51 | window[AN] = n; | |
52 | window[AS] = s; | |
53 | window[AE] = e; | |
54 | window[AW] = w; | |
55 | /* set x and y to midpoints of rectangle */ | |
56 | window[AY] = s + (n - s)/2.0; | |
57 | window[AX] = w + (e - w)/2.0; | |
58 | } | |
59 | \f | |
60 | ||
61 | /* Return width of a bar line. Allow a couple pixels on either side | |
62 | * of the actual line(s) [and dots]. Does not include user padding. | |
63 | * Since an invisbar has no lines or dots, it has zero width. | |
64 | */ | |
65 | ||
66 | double | |
67 | width_barline(bar_p) | |
68 | ||
69 | struct BAR *bar_p; /* return width of this bar line */ | |
70 | ||
71 | { | |
72 | if (bar_p == (struct BAR *) 0) { | |
73 | return(0.0); | |
74 | } | |
75 | ||
76 | switch(bar_p->bartype) { | |
77 | ||
78 | case SINGLEBAR: | |
79 | return(7 * STDPAD); | |
80 | ||
81 | case DOUBLEBAR: | |
82 | return(9 * STDPAD); | |
83 | ||
84 | case ENDBAR: | |
85 | return(12 * STDPAD); | |
86 | ||
87 | case REPEATSTART: | |
88 | case REPEATEND: | |
89 | return(16 * STDPAD); | |
90 | ||
91 | case REPEATBOTH: | |
92 | return(19 * STDPAD); | |
93 | ||
94 | case RESTART: | |
95 | return(2.0 * HALF_RESTART_WIDTH); | |
96 | ||
97 | case INVISBAR: | |
98 | return(0.0); | |
99 | ||
100 | default: | |
101 | pfatal("bad bar type"); | |
102 | /*NOTREACHED*/ | |
103 | break; | |
104 | } | |
105 | ||
106 | /*NOTREACHED*/ | |
107 | return(0.0); | |
108 | } | |
109 | \f | |
110 | ||
111 | /* Normally, we want some padding on both sides of a bar line, | |
112 | * but at the end of a staff, we don't want right padding. | |
113 | * This applies either if we are at the right | |
114 | * margin or if the next bar is a restart. | |
115 | * This function returns how much to adjust an end-of-score bar line | |
116 | * eastward to make it at the right edge of the score. | |
117 | */ | |
118 | ||
119 | double | |
120 | eos_bar_adjust(bar_p) | |
121 | ||
122 | struct BAR *bar_p; /* the bar to adjust */ | |
123 | ||
124 | { | |
125 | double halfbarwidth; | |
126 | ||
127 | halfbarwidth = width_barline(bar_p) / 2.0; | |
128 | switch (bar_p->bartype) { | |
129 | case DOUBLEBAR: | |
130 | return(halfbarwidth - STDPAD - (W_NORMAL / PPI / 2.0)); | |
131 | case SINGLEBAR: | |
132 | return(halfbarwidth - (W_NORMAL / PPI / 2.0)); | |
133 | case REPEATEND: | |
134 | return(halfbarwidth - (4.0 * STDPAD) - (W_WIDE / PPI / 2.0)); | |
135 | case ENDBAR: | |
136 | return(halfbarwidth - (2.0 * STDPAD) - (W_WIDE / PPI / 2.0)); | |
137 | default: | |
138 | break; | |
139 | } | |
140 | return(0.0); | |
141 | } | |
142 | \f | |
143 | ||
144 | /* width of clef, keysig, timesig */ | |
145 | ||
146 | double | |
147 | width_clefsig(clefsig_p) | |
148 | ||
149 | struct CLEFSIG *clefsig_p; /* return width of this clefsig */ | |
150 | ||
151 | { | |
152 | /* we just call the routine to print a clefsig, but with | |
153 | * flag to tell it to not really print */ | |
154 | return(pr_clefsig((struct MAINLL *) 0, clefsig_p, NO)); | |
155 | } | |
156 | \f | |
157 | ||
158 | /* translate clef name to clef output character */ | |
159 | ||
160 | int | |
161 | clefchar(clef) | |
162 | ||
163 | int clef; /* TREBLE, etc */ | |
164 | ||
165 | { | |
166 | switch(clef) { | |
167 | ||
168 | case TREBLE: | |
169 | case TREBLE_8: | |
170 | case FRENCHVIOLIN: | |
171 | case TREBLE_8A: | |
172 | return(C_GCLEF); | |
173 | ||
174 | case BASS: | |
175 | return(C_FCLEF); | |
176 | ||
177 | default: | |
178 | /* everything else uses the C clef */ | |
179 | return(C_CCLEF); | |
180 | } | |
181 | } | |
182 | \f | |
183 | ||
184 | /* Returns width of the given clef in inches in the default size. | |
185 | * If is_small is YES, give width of the 3/4 sized one used in mid-score, | |
186 | * rather than the full-sized used at beginning of line. | |
187 | * Caller must adjust by staffscale if they need that. | |
188 | * No padding is included beyond the padding of the clef music character | |
189 | * itself, so caller needs to add any they deem appropriate for aesthetics. | |
190 | */ | |
191 | ||
192 | double | |
193 | clefwidth(clef, is_small) | |
194 | ||
195 | int clef; /* TREBLE, BASS, ALTO, FRENCHVIOLIN, etc */ | |
196 | int is_small; /* If YES, assume mid-score clef, not full sized one */ | |
197 | ||
198 | { | |
199 | return(width(FONT_MUSIC, (is_small ? (3 * DFLT_SIZE) / 4 : DFLT_SIZE), | |
200 | clefchar(clef))); | |
201 | } | |
202 | \f | |
203 | ||
204 | /* Returns where the given clef's baseline should be | |
205 | * relative to the middle line of the staff, in stepsizes. | |
206 | * (Above the middle line is positive, below is negative). | |
207 | * If north_p and/or south_p are non-null, the relative north/south values | |
208 | * of the clef are returned via the pointers. These will be relative | |
209 | * to the middle line of the staff and will be in inches | |
210 | * in the default staffscale, using default size | |
211 | * (unless is_small == YES, in which case it will be 3/4 size). | |
212 | * Note that this should not be called with TABCLEF or NOCLEF. | |
213 | */ | |
214 | ||
215 | int | |
216 | clefvert(clef, is_small, north_p, south_p) | |
217 | ||
218 | int clef; /* TREBLE, BASS, ALTO, FRENCHVIOLIN, etc */ | |
219 | int is_small; /* If YES, assume mid-score clef, not full sized one. | |
220 | * Note that if both of the following arguments are null, | |
221 | * this is_small argument's value is actually irrelevent. */ | |
222 | float *north_p; /* if non-null, relative north will be returned here */ | |
223 | float *south_p; /* if non-null, relative south will be returned here */ | |
224 | ||
225 | { | |
226 | int steps; /* relative to middle line, to be returned */ | |
227 | ||
228 | switch(clef) { | |
229 | ||
230 | case TREBLE: | |
231 | case TREBLE_8: | |
232 | case TREBLE_8A: | |
233 | steps = -2; | |
234 | break; | |
235 | ||
236 | case FRENCHVIOLIN: | |
237 | case SOPRANO: | |
238 | steps = -4; | |
239 | break; | |
240 | ||
241 | case MEZZOSOPRANO: | |
242 | steps = -2; | |
243 | break; | |
244 | ||
245 | case ALTO: | |
246 | steps = 0; | |
247 | break; | |
248 | ||
249 | case TENOR: | |
250 | steps = 2; | |
251 | break; | |
252 | ||
253 | case BARITONE: | |
254 | steps = 4; | |
255 | break; | |
256 | ||
257 | case BASS: | |
258 | steps = 2; | |
259 | break; | |
260 | ||
261 | case TABCLEF: | |
262 | default: | |
263 | pfatal("clefvert called with invalid clef %d", clef); | |
264 | /*NOTREACHED*/ | |
265 | steps = 0; /* shut up bogus compiler warning */ | |
266 | break; | |
267 | } | |
268 | ||
269 | /* If caller wants relative north/south values, calculate them */ | |
270 | if (north_p != 0 || south_p != 0) { | |
271 | char muschar; /* music character to print for the clef */ | |
272 | int clefsize; | |
273 | char tr8str[4]; /* "8" of treble8 or 8treble */ | |
274 | float value; /* of north or south */ | |
275 | ||
276 | muschar = clefchar(clef); | |
277 | clefsize = (is_small ? (3 * DFLT_SIZE) / 4 : DFLT_SIZE); | |
278 | tr8str[0] = FONT_TI; | |
279 | tr8str[1] = 9; | |
280 | tr8str[2] = '8'; | |
281 | tr8str[3] = '\0'; | |
282 | ||
283 | if (north_p != 0) { | |
284 | value = (float) ascent(FONT_MUSIC, clefsize, muschar); | |
285 | if (clef == TREBLE_8A) { | |
286 | value += (float) strheight(tr8str); | |
287 | } | |
288 | *north_p = value + (float)(steps * STEPSIZE); | |
289 | } | |
290 | ||
291 | if (south_p != 0) { | |
292 | value = (float) descent(FONT_MUSIC, clefsize, muschar); | |
293 | if (clef == TREBLE_8) { | |
294 | value += (float) strheight(tr8str); | |
295 | } | |
296 | *south_p = -value + (float)(steps * STEPSIZE); | |
297 | } | |
298 | } | |
299 | ||
300 | return(steps); | |
301 | } | |
302 | \f | |
303 | ||
304 | /* Given a BLOCKHEAD, fill in its height. BLOCKHEADs are a bit strange, | |
305 | * in that they are in a separate coordinate space of unknown size. | |
306 | * So we start out assuming it is infinitely thin. Then we check | |
307 | * each string in the list and keep track of the lowest one, by | |
308 | * pretending to go where it would be printed and adding the descent | |
309 | * of the string. At the end, the height must be the page height minus the | |
310 | * lowest, since upwards is positive */ | |
311 | ||
312 | static void | |
313 | set_height_blockhead(blockhead_p, context, mll_p) | |
314 | ||
315 | struct BLOCKHEAD *blockhead_p; /* which block to get height of */ | |
316 | int context; /* C_HEADER, etc */ | |
317 | struct MAINLL *mll_p; /* for getting margin overrides */ | |
318 | ||
319 | { | |
320 | float distance; /* of headfoot from bottom of page */ | |
321 | float lowest; | |
322 | float x_offset; /* because of justification */ | |
323 | float yval; /* y coordinate value */ | |
324 | struct PRINTDATA *pr_p; /* walk through list of things to print */ | |
325 | float block_width; /* page width minus margins */ | |
326 | float s_descent; /* strdescent() of the current string */ | |
327 | float extra; /* how much farther the string descended | |
328 | * than would be expected of a normal, | |
329 | * single line. */ | |
330 | struct MAINLL *rightmargin_mll_p; /* mll_p to use for | |
331 | * finding the right margin */ | |
332 | ||
333 | ||
334 | /* Set _win in this context to zero height at top margin */ | |
335 | Context = context; | |
336 | rightmargin_mll_p = (mll_p ? mll_p->next : 0); | |
337 | set_win_coord(blockhead_p->c); | |
338 | set_win(PGHEIGHT - EFF_TOPMARGIN, PGHEIGHT - EFF_TOPMARGIN, | |
339 | PGWIDTH - eff_rightmargin(rightmargin_mll_p), | |
340 | eff_leftmargin(mll_p)); | |
341 | block_width = PGWIDTH - eff_rightmargin(rightmargin_mll_p) - | |
342 | eff_leftmargin(mll_p); | |
343 | ||
344 | if (blockhead_p->printdata_p != (struct PRINTDATA *) 0) { | |
345 | /* set current to left corner */ | |
346 | set_cur(eff_leftmargin((struct MAINLL *)0), | |
347 | PGHEIGHT - EFF_TOPMARGIN); | |
348 | ||
349 | distance = _Cur[AY]; | |
350 | ||
351 | /* Process each item in the list */ | |
352 | for (pr_p = blockhead_p->printdata_p; | |
353 | pr_p != (struct PRINTDATA *) 0; | |
354 | pr_p = pr_p->next) { | |
355 | ||
356 | /* If this is a paragraph, | |
357 | * split it into as many lines as needed. */ | |
358 | if (pr_p->justifytype == J_JUSTPARA || | |
359 | pr_p->justifytype == J_RAGPARA) { | |
360 | pr_p->string = split_string(pr_p->string, | |
361 | block_width); | |
362 | } | |
363 | pr_p->width = strwidth(pr_p->string); | |
364 | /* stretch justified paragraphs to full width */ | |
365 | if (pr_p->justifytype == J_JUSTPARA && | |
366 | pr_p->width < block_width) { | |
367 | pr_p->width = block_width; | |
368 | } | |
369 | ||
370 | /* adjust for justification */ | |
371 | switch (pr_p->justifytype) { | |
372 | ||
373 | case J_RIGHT: | |
374 | x_offset = pr_p->width; | |
375 | break; | |
376 | ||
377 | case J_CENTER: | |
378 | x_offset = pr_p->width / 2.0; | |
379 | break; | |
380 | ||
381 | default: | |
382 | x_offset = 0.0; | |
383 | break; | |
384 | } | |
385 | ||
386 | /* set current to specified location */ | |
387 | yval = inpc_y (&(pr_p->location), (char *) 0, -1); | |
388 | set_cur( inpc_x( &(pr_p->location), (char *) 0, -1 ) | |
389 | - x_offset, yval); | |
390 | ||
391 | /* if user said to go off of south or y of _win, | |
392 | * change to equivalent offset off of north of _win. | |
393 | * because the south and y could change */ | |
394 | if (pr_p->location.vtype == AS || | |
395 | pr_p->location.vtype == AY) { | |
396 | if (pr_p->location.vert_p == blockhead_p->c) { | |
397 | pr_p->location.vtype = AN; | |
398 | pr_p->location.vsteps = (yval | |
399 | - (PGHEIGHT - EFF_TOPMARGIN) | |
400 | ) / STEPSIZE; | |
401 | } | |
402 | } | |
403 | ||
404 | /* determine lowest descent of current string */ | |
405 | if (pr_p->isPostScript == YES) { | |
406 | s_descent = 0.0; | |
407 | } | |
408 | else { | |
409 | s_descent = strdescent(pr_p->string); | |
410 | } | |
411 | lowest = _Cur[AY] - s_descent; | |
412 | ||
413 | /* if lowest of anything found so far, note that */ | |
414 | if ( lowest < distance) { | |
415 | distance = lowest; | |
416 | set_win(PGHEIGHT - EFF_TOPMARGIN, distance, | |
417 | PGWIDTH - eff_rightmargin((struct MAINLL *)0), | |
418 | eff_leftmargin((struct MAINLL *)0)); | |
419 | } | |
420 | ||
421 | /* Set to end of string just "printed." | |
422 | * If the string when down farther than a single line | |
423 | * add in that extra. | |
424 | */ | |
425 | if (pr_p->isPostScript == YES) { | |
426 | extra = 0.0; | |
427 | } | |
428 | else { | |
429 | extra = s_descent - fontdescent(pr_p->string[0], | |
430 | pr_p->string[1]); | |
431 | if (extra < 0.0) { | |
432 | extra = 0.0; | |
433 | } | |
434 | } | |
435 | set_cur( _Cur[AX] + pr_p->width, _Cur[AY] - extra); | |
436 | } | |
437 | ||
438 | /* set height to lowest distance encountered */ | |
439 | blockhead_p->height = (PGHEIGHT - distance - EFF_TOPMARGIN); | |
440 | ||
441 | } | |
442 | else { | |
443 | /* empty header/footer */ | |
444 | blockhead_p->height = 0.0; | |
445 | } | |
446 | ||
447 | /* if was a footer, now we can set the actual _win coordinates, | |
448 | * by offsetting from bottom of page instead of top */ | |
449 | if ( (context == C_FOOTER) || (context == C_FOOT2) ) { | |
450 | set_win(EFF_BOTMARGIN + blockhead_p->height, EFF_BOTMARGIN, | |
451 | PGWIDTH - eff_rightmargin((struct MAINLL *)0), | |
452 | eff_leftmargin((struct MAINLL *)0)); | |
453 | } | |
454 | set_win_coord(0); | |
455 | } | |
456 | \f | |
457 | ||
458 | /* Calculate the height of all blocks, including headers and footers, | |
459 | * and fill in the height field of the struct. */ | |
460 | ||
461 | void | |
462 | calc_block_heights() | |
463 | ||
464 | { | |
465 | struct MAINLL *mll_p; | |
466 | double topheight = -1.0; /* if > 0.0, is height of "top" */ | |
467 | double botheight = -1.0; /* if > 0.0, is height of "bottom" */ | |
468 | ||
469 | debug(2, "calc_block_heights"); | |
470 | ||
471 | set_height_blockhead(&Header, C_HEADER, 0); | |
472 | set_height_blockhead(&Footer, C_FOOTER, 0); | |
473 | set_height_blockhead(&Header2, C_HEAD2, 0); | |
474 | set_height_blockhead(&Footer2, C_FOOT2, 0); | |
475 | ||
476 | /* set main _win to space within margins and header/footer | |
477 | * for first page. */ | |
478 | Context = C_MUSIC; | |
479 | ||
480 | /* set the size of _page */ | |
481 | _Page[AW] = _Page[AS] = 0.0; | |
482 | _Page[AE] = PGWIDTH; | |
483 | _Page[AN] = PGHEIGHT; | |
484 | _Page[AX] = PGWIDTH / 2.0; | |
485 | _Page[AY] = PGHEIGHT / 2.0; | |
486 | ||
487 | /* now calculate top/bot and any other blocks in the main list */ | |
488 | initstructs(); | |
489 | for (mll_p = Mainllhc_p; mll_p != 0; mll_p = mll_p->next) { | |
490 | if (mll_p->str == S_SSV) { | |
491 | /* keep margins up to date */ | |
492 | asgnssv(mll_p->u.ssv_p); | |
493 | } | |
494 | else if (mll_p->str == S_FEED) { | |
495 | if (mll_p->u.feed_p->top_p != 0) { | |
496 | set_height_blockhead(mll_p->u.feed_p->top_p, | |
497 | C_TOP, 0); | |
498 | if (topheight < 0.0) { | |
499 | /* save for setting music _win */ | |
500 | topheight = mll_p->u.feed_p->top_p->height; | |
501 | } | |
502 | } | |
503 | if (mll_p->u.feed_p->top2_p != 0) { | |
504 | set_height_blockhead(mll_p->u.feed_p->top2_p, | |
505 | C_TOP2, 0); | |
506 | } | |
507 | if (mll_p->u.feed_p->bot_p != 0) { | |
508 | set_height_blockhead(mll_p->u.feed_p->bot_p, | |
509 | C_BOT, 0); | |
510 | if (botheight < 0.0) { | |
511 | /* save for setting music _win */ | |
512 | botheight = mll_p->u.feed_p->bot_p->height; | |
513 | } | |
514 | } | |
515 | if (mll_p->u.feed_p->bot2_p != 0) { | |
516 | set_height_blockhead(mll_p->u.feed_p->bot2_p, | |
517 | C_BOT2, 0); | |
518 | } | |
519 | } | |
520 | else if (mll_p->str == S_BLOCKHEAD) { | |
521 | set_height_blockhead(mll_p->u.blockhead_p, | |
522 | C_BLOCK, mll_p); | |
523 | } | |
524 | } | |
525 | ||
526 | set_win(PGHEIGHT - EFF_TOPMARGIN - Header.height | |
527 | - (topheight > 0.0 ? topheight : 0.0), | |
528 | EFF_BOTMARGIN + Footer.height | |
529 | + (botheight > 0.0 ? botheight : 0.0), | |
530 | PGWIDTH - eff_rightmargin((struct MAINLL *)0), | |
531 | eff_leftmargin((struct MAINLL *)0)); | |
532 | } | |
533 | \f | |
534 | ||
535 | /* return number of beams or flags to use for a given basic time */ | |
536 | ||
537 | int | |
538 | numbeams(btime) | |
539 | ||
540 | int btime; /* basic time of note to be checked */ | |
541 | ||
542 | { | |
543 | int n; | |
544 | ||
545 | /* no beams for long notes */ | |
546 | if (btime <= 4) { | |
547 | return(0); | |
548 | } | |
549 | ||
550 | /* number of beams is equal to the number of bits 4 has to be | |
551 | * shifted left in order to equal the given basic time */ | |
552 | for (n = 1; (4 << n) <= MAXBASICTIME; n++) { | |
553 | if (btime == (4 << n)) { | |
554 | return(n); | |
555 | } | |
556 | } | |
557 | return(0); | |
558 | } | |
559 | \f | |
560 | ||
561 | /* given an accidental (#, &, x, B, n) return its music character | |
562 | * C_SHARP, etc of the proper size. If not a valid accidental, | |
563 | * return 0 */ | |
564 | ||
565 | int acc2char(acc) | |
566 | ||
567 | int acc; | |
568 | ||
569 | ||
570 | { | |
571 | switch (acc) { | |
572 | ||
573 | case '&': | |
574 | return(C_FLAT); | |
575 | case '#': | |
576 | return(C_SHARP); | |
577 | case 'n': | |
578 | return(C_NAT); | |
579 | case 'x': | |
580 | return(C_DBLSHARP); | |
581 | case 'B': | |
582 | return(C_DBLFLAT); | |
583 | default: | |
584 | /* no accidental */ | |
585 | return(0); | |
586 | } | |
587 | } | |
588 | \f | |
589 | ||
590 | /* get the absolute x and y values for an INPCOORD */ | |
591 | /* get the proper one of the coordinates of the specified location, and | |
592 | * add in any offsets */ | |
593 | ||
594 | double | |
595 | inpc_x(inpcoord_p, fname, lineno) | |
596 | ||
597 | struct INPCOORD *inpcoord_p; /* return the x value of this inpcoord */ | |
598 | char *fname; /* filename, for error message */ | |
599 | int lineno; /* for error message */ | |
600 | ||
601 | { | |
602 | double retval; | |
603 | ||
604 | ||
605 | /* if hor_p is null, then this is an absolute coord, rather | |
606 | * than relative to some variable */ | |
607 | if (inpcoord_p->hor_p == (float *) 0) { | |
608 | if (inpcoord_p->counts != 0.0) { | |
609 | /* parser should have blocked this case */ | |
610 | pfatal("can't specify time offset if no variable specified"); | |
611 | } | |
612 | retval = inpcoord_p->hsteps * STEPSIZE; | |
613 | } | |
614 | ||
615 | /* X location is the x, e, or w value of the specified location | |
616 | * variable, plus any offset plus any time offset */ | |
617 | else { | |
618 | retval = inpcoord_p->hor_p [ inpcoord_p->htype ] | |
619 | + inpcoord_p->hsteps * STEPSIZE | |
620 | * coord_staffscale(inpcoord_p->hor_p) | |
621 | + ( inpcoord_p->counts * inpcoord_p->hor_p [INCHPERWHOLE] / | |
622 | (double) Score.timeden ); | |
623 | } | |
624 | ||
625 | if (retval < 0.0 || retval > PGWIDTH) { | |
626 | if (lineno > 0 && fname != (char *) 0) { | |
627 | l_warning(fname, lineno, | |
628 | "x value of %f is off the page", retval); | |
629 | } | |
630 | } | |
631 | return(retval); | |
632 | } | |
633 | \f | |
634 | ||
635 | /* given an inpcoord, return its y coordinate */ | |
636 | ||
637 | double | |
638 | inpc_y(inpcoord_p, fname, lineno) | |
639 | ||
640 | struct INPCOORD *inpcoord_p; /* return y value of this inpcoord */ | |
641 | char *fname; /* filename, for error message */ | |
642 | int lineno; /* for error message */ | |
643 | ||
644 | { | |
645 | double retval; | |
646 | ||
647 | ||
648 | /* if vert_p is null, then this is absolute rather than relative */ | |
649 | if ( inpcoord_p->vert_p == (float *) 0) { | |
650 | retval = inpcoord_p->vsteps * STEPSIZE; | |
651 | } | |
652 | ||
653 | /* Y value is y, n, or s value of specified location variable | |
654 | * plus any vertical offset plus any vsteps offset */ | |
655 | else { | |
656 | retval = inpcoord_p->vert_p [ inpcoord_p->vtype ] | |
657 | + (inpcoord_p->vsteps * STEPSIZE | |
658 | * coord_staffscale(inpcoord_p->vert_p)); | |
659 | } | |
660 | ||
661 | if (retval < 0.0 || retval > PGHEIGHT) { | |
662 | if (lineno > 0 && fname != (char *) 0) { | |
663 | l_warning(fname, lineno, | |
664 | "y value of %f is off the page", retval); | |
665 | } | |
666 | } | |
667 | return(retval); | |
668 | } | |
669 | \f | |
670 | ||
671 | /* Given an INPCOORD, return the appropriate staffscale value. Look | |
672 | * up which staff, if any, the INPCOORD is associated with, and then get | |
673 | * the staffscale out of the SSVs. | |
674 | */ | |
675 | ||
676 | static double | |
677 | coord_staffscale(coord_array) | |
678 | ||
679 | float *coord_array; | |
680 | ||
681 | { | |
682 | struct COORD_INFO *coord_info_p; | |
683 | ||
684 | ||
685 | /* figure out what staffscale value to use, based on | |
686 | * which staff the coordinate is associated with */ | |
687 | if ((coord_info_p = find_coord(coord_array)) | |
688 | != (struct COORD_INFO *) 0 && | |
689 | coord_info_p->staffno != 0) { | |
690 | return(svpath(coord_info_p->staffno, STAFFSCALE)->staffscale); | |
691 | } | |
692 | else { | |
693 | return(1.0); | |
694 | } | |
695 | } | |
696 | \f | |
697 | ||
698 | /* return the y coordinate of the end of a note stem */ | |
699 | /* (the end farthest from the note head) */ | |
700 | ||
701 | double | |
702 | find_y_stem(gs_p) | |
703 | ||
704 | struct GRPSYL *gs_p; /* which group to get the stem of */ | |
705 | ||
706 | { | |
707 | /* error checks */ | |
708 | if (gs_p == (struct GRPSYL *) 0) { | |
709 | pfatal("null group passed to find_y_stem"); | |
710 | } | |
711 | ||
712 | if (gs_p->nnotes == 0) { | |
713 | pfatal("group with no notes passed to find_y_stem (from line %d, grpcont %d)", | |
714 | gs_p->inputlineno, gs_p->grpcont); | |
715 | } | |
716 | ||
717 | /* if stem is up, start at bottom note, if down at top */ | |
718 | if (gs_p->stemdir == UP) { | |
719 | return(gs_p->notelist[ gs_p->nnotes - 1].c[AY] + gs_p->stemlen); | |
720 | } | |
721 | else { | |
722 | return(gs_p->notelist[0].c[AY] - gs_p->stemlen); | |
723 | } | |
724 | } | |
725 | \f | |
726 | ||
727 | /* return x coordinate of a note stem */ | |
728 | ||
729 | double | |
730 | find_x_stem(gs_p) | |
731 | ||
732 | struct GRPSYL *gs_p; /* return x of stem of this group */ | |
733 | ||
734 | { | |
735 | double stem_adjust; /* to overlap the note head */ | |
736 | ||
737 | if ( gs_p == (struct GRPSYL *) 0) { | |
738 | pfatal("bad group passed to find_x_stem"); | |
739 | } | |
740 | ||
741 | /* if called with something longer than a half note, then there | |
742 | * is no real stem. We must be being called for printing slashes, | |
743 | * so in that case, the x of the "stem" is the x of the group */ | |
744 | if (gs_p->basictime < 2) { | |
745 | return(gs_p->c[AX]); | |
746 | } | |
747 | ||
748 | /* move stem by half of stem width so edge lines up with edge of note */ | |
749 | stem_adjust = W_NORMAL / PPI / 2.0; | |
750 | if (gs_p->stemdir == UP) { | |
751 | stem_adjust = -stem_adjust; | |
752 | } | |
753 | return(gs_p->c[AX] + (gs_p->stemx + stem_adjust) * Staffscale); | |
754 | } | |
755 | \f | |
756 | ||
757 | /* return the width of a key signature in inches */ | |
758 | ||
759 | double | |
760 | width_keysig(sharps, naturals) | |
761 | ||
762 | int sharps; /* how many sharps to print, or if negative, how many flats. */ | |
763 | int naturals; /* how many naturals to print for canceling previous key */ | |
764 | ||
765 | { | |
766 | double total_width = 0.0; | |
767 | int size; | |
768 | ||
769 | /* In keysig, things are drawn closer together than | |
770 | * in other places, so to get the total width, we first | |
771 | * multiply the width of the sharp, flat, or natural character | |
772 | * by the number of times it is to be printed, then subtract off | |
773 | * two points for each character printed, except for naturals, | |
774 | * which are only jammed together by one point. */ | |
775 | ||
776 | size = adj_size(DFLT_SIZE, Staffscale, (char *) 0, -1); | |
777 | if (sharps >= 1) { | |
778 | total_width = (width(FONT_MUSIC, size, C_SHARP) - 2.0 * Stdpad) | |
779 | * sharps; | |
780 | } | |
781 | else if (sharps <= -1) { | |
782 | /* negative sharps are flats */ | |
783 | total_width = (width(FONT_MUSIC, size, C_FLAT) - 2.0 * Stdpad) | |
784 | * -sharps; | |
785 | } | |
786 | if (naturals != 0) { | |
787 | total_width += (width(FONT_MUSIC, size, C_NAT) - Stdpad) | |
788 | * abs(naturals) + 3.0 * Stdpad; | |
789 | } | |
790 | return(total_width); | |
791 | } | |
792 | \f | |
793 | /* | |
794 | * Name: nextgrpsyl() | |
795 | * | |
796 | * Abstract: Find next GRPSYL in this voice (same measure or not). | |
797 | * | |
798 | * Returns: Pointer to the GRPSYL, or 0 if none. | |
799 | * | |
800 | * Description: This function, given a GRPSYL and the MLL structure it hangs | |
801 | * off of, returns the next GRPSYL in this voice, even if it's in | |
802 | * the next measure. If it is in the next measure, *mll_p_p gets | |
803 | * updated. But if that next measure is a second or later ending, | |
804 | * it's not considered to be a "next" measure, so return 0. | |
805 | */ | |
806 | ||
807 | struct GRPSYL * | |
808 | nextgrpsyl(gs_p, mll_p_p) | |
809 | ||
810 | struct GRPSYL *gs_p; /* the given GRPSYL */ | |
811 | struct MAINLL **mll_p_p; /* main linked list structure it is hanging off of */ | |
812 | ||
813 | { | |
814 | struct MAINLL *mll_p; /* point at a MLL item */ | |
815 | int endingloc; /* of the following barline */ | |
816 | ||
817 | ||
818 | /* if not at end of measure, just return the next GRPSYL */ | |
819 | if (gs_p->next != 0) { | |
820 | return (gs_p->next); | |
821 | } | |
822 | ||
823 | mll_p = *mll_p_p; /* save original MLL item */ | |
824 | ||
825 | /* | |
826 | * We hit the end of the measure. We need to find the first group in | |
827 | * the next measure. Find the coming bar line, then the corresponding | |
828 | * staff in the next measure. We do this in case the number of staffs | |
829 | * changes back and forth; we don't want to find the staff in some | |
830 | * later measure. | |
831 | */ | |
832 | for (*mll_p_p = (*mll_p_p)->next; *mll_p_p != (struct MAINLL *) 0 && | |
833 | (*mll_p_p)->str != S_BAR; *mll_p_p = (*mll_p_p)->next) { | |
834 | ; | |
835 | } | |
836 | ||
837 | /* if we hit the end of the MLL, there is no next GRPSYL */ | |
838 | if (*mll_p_p == (struct MAINLL *) 0) { | |
839 | return (struct GRPSYL *) 0; | |
840 | } | |
841 | ||
842 | /* we found a bar; get its endingloc */ | |
843 | endingloc = (*mll_p_p)->u.bar_p->endingloc; | |
844 | ||
845 | /* | |
846 | * Search for this staff in next measure. If we find a pseudobar while | |
847 | * doing this, save its endingloc in preference to the real bar's. | |
848 | */ | |
849 | for (*mll_p_p = (*mll_p_p)->next; *mll_p_p != (struct MAINLL *) 0 && | |
850 | (*mll_p_p)->str != S_BAR && | |
851 | ((*mll_p_p)->str != S_STAFF || | |
852 | (*mll_p_p)->u.staff_p->staffno != gs_p->staffno); | |
853 | *mll_p_p = (*mll_p_p)->next) { | |
854 | ||
855 | if ((*mll_p_p)->str == S_CLEFSIG && | |
856 | (*mll_p_p)->u.clefsig_p->bar_p != (struct BAR *) 0) { | |
857 | endingloc = (*mll_p_p)->u.clefsig_p->bar_p->endingloc; | |
858 | } | |
859 | } | |
860 | ||
861 | /* if we hit the end or another bar before finding our staff, return */ | |
862 | if (*mll_p_p == (struct MAINLL *) 0 || (*mll_p_p)->str == S_BAR) { | |
863 | return (struct GRPSYL *) 0; | |
864 | } | |
865 | ||
866 | /* | |
867 | * We found the appropriate staff in the next measure. But if we have | |
868 | * crossed into a second or later ending, this bar doesn't really | |
869 | * "follow" the previous bar, and we must return null. So if endingloc | |
870 | * shows this is the case, we must search backwards to find out if we | |
871 | * were already in an ending. | |
872 | */ | |
873 | if (endingloc == STARTITEM) { | |
874 | while (mll_p != 0 && mll_p->str != S_BAR && (mll_p->str != | |
875 | S_CLEFSIG || mll_p->u.clefsig_p->bar_p == 0)) | |
876 | mll_p = mll_p->prev; | |
877 | ||
878 | /* set endingloc of the previous measure */ | |
879 | if (mll_p == 0) { | |
880 | endingloc = NOITEM; | |
881 | } else if (mll_p->str == S_BAR) { | |
882 | endingloc = mll_p->u.bar_p->endingloc; | |
883 | } else { | |
884 | endingloc = mll_p->u.clefsig_p->bar_p->endingloc; | |
885 | } | |
886 | ||
887 | /* if we were already in an ending, there's no next GRPSYL */ | |
888 | if (endingloc == STARTITEM || endingloc == INITEM) { | |
889 | return (struct GRPSYL *) 0; | |
890 | } | |
891 | } | |
892 | ||
893 | /* return the first GRPSYL of the appropriate voice */ | |
894 | return ((*mll_p_p)->u.staff_p->groups_p[ gs_p->vno - 1 ]); | |
895 | } | |
896 | \f | |
897 | /* | |
898 | * Name: prevgrpsyl() | |
899 | * | |
900 | * Abstract: Find previous GRPSYL in this voice (same measure or not). | |
901 | * | |
902 | * Returns: Pointer to the GRPSYL, or 0 if none. | |
903 | * | |
904 | * Description: This function, given a GRPSYL and the MLL structure it hangs | |
905 | * off of, returns the previous GRPSYL in this voice, even if it's | |
906 | * in an earlier measure. If we are at the start of an ending, | |
907 | * it skips over any previous ending and goes to the measure | |
908 | * preceding the first ending. If the resulting GRPSYL is in a | |
909 | * previous measure, *mll_p_p gets updated. | |
910 | */ | |
911 | ||
912 | struct GRPSYL * | |
913 | prevgrpsyl(gs_p, mll_p_p) | |
914 | ||
915 | struct GRPSYL *gs_p; /* the given GRPSYL */ | |
916 | struct MAINLL **mll_p_p; /* main linked list structure it is hanging off of */ | |
917 | ||
918 | { | |
919 | struct GRPSYL *gs2_p; /* for looping through prev measure's list */ | |
920 | struct BAR *bar_p; /* point at a bar line */ | |
921 | struct MAINLL *mll_p; /* point at a MLL item */ | |
922 | int pseudo; /* was the last thing we saw a pseudobar? */ | |
923 | int barcount; /* how many bar lines we looped backward thru*/ | |
924 | int safmoae; /* "started at first measure of an ending" */ | |
925 | ||
926 | ||
927 | /* if not at start of measure, just return the previous GRPSYL */ | |
928 | if (gs_p->prev != (struct GRPSYL *) 0) { | |
929 | return (gs_p->prev); | |
930 | } | |
931 | ||
932 | /* | |
933 | * We hit the start of the measure. Loop backwards through the MLL | |
934 | * looking for the bar line at the start of the "previous" measure. | |
935 | * If our measure is not the first measure of an ending, this is | |
936 | * simply the bar at the start of the previous measure. Otherwise, | |
937 | * this is the bar before the measure before the first ending. Also | |
938 | * handle the cases where we fall off the start of the MLL. | |
939 | */ | |
940 | bar_p = 0; | |
941 | mll_p = *mll_p_p; | |
942 | pseudo = NO; | |
943 | barcount = 0; | |
944 | safmoae = NO; | |
945 | do { | |
946 | /* find preceding bar or pseudobar, if either exists */ | |
947 | for (mll_p = mll_p->prev; mll_p != (struct MAINLL *) 0 && | |
948 | mll_p->str != S_BAR && | |
949 | (mll_p->str != S_CLEFSIG || | |
950 | mll_p->u.clefsig_p->bar_p == 0); | |
951 | mll_p = mll_p->prev) { | |
952 | ; | |
953 | } | |
954 | ||
955 | /* | |
956 | * If we hit the start of the MLL without crossing any bars, or | |
957 | * just a pseudobar, there is no preceding GRPSYL, so return 0. | |
958 | * (Depending on who is calling this function, the pseudobar at | |
959 | * the start of the song may or may not exist.) Otherwise, it | |
960 | * must be that we started in the second measure, or an ending | |
961 | * that we skipped over started there. Point at the start of | |
962 | * the MLL, and get out of the loop. Note that we can't still | |
963 | * be in the process of skipping over endings: no ending can | |
964 | * start at the first measure of the song, because there is no | |
965 | * bar line there. | |
966 | */ | |
967 | if (mll_p == 0) { | |
968 | if (barcount == 0 || (barcount == 1 && pseudo == YES)) { | |
969 | return (struct GRPSYL *) 0; | |
970 | } | |
971 | mll_p = Mainllhc_p; | |
972 | break; | |
973 | } | |
974 | ||
975 | barcount++; | |
976 | ||
977 | /* | |
978 | * Point bar_p at the relevant bar/pseudobar for checking the | |
979 | * endingloc. If this is a pseudobar, it's relevant. If this | |
980 | * is a bar, it's relevant only if it's the first thing we've | |
981 | * seen, or the thing we saw last was not a pseudobar. That | |
982 | * is, the endingloc of the bar at the end of a score is to be | |
983 | * ignored, because the true endingloc has been moved to the | |
984 | * next score's pseudobar. We need to worry about this because | |
985 | * of the case where a second ending starts at the start of the | |
986 | * new score (STARTITEM) and the previous score ends with | |
987 | * ENDITEM, which should be ignored. | |
988 | */ | |
989 | if (mll_p->str == S_BAR) { | |
990 | if (bar_p == 0 || pseudo == NO) { | |
991 | bar_p = mll_p->u.bar_p; | |
992 | } | |
993 | if (pseudo == YES) { | |
994 | barcount--; /* forget this bar */ | |
995 | pseudo = NO; | |
996 | } | |
997 | } else { | |
998 | bar_p = mll_p->u.clefsig_p->bar_p; | |
999 | pseudo = YES; | |
1000 | } | |
1001 | ||
1002 | /* | |
1003 | * If this is the first measure we're backing into, and this | |
1004 | * first bar we hit shows that our GRPSYL was in the first | |
1005 | * measure of an ending, remember that fact. | |
1006 | */ | |
1007 | if (barcount == 1 && bar_p->endingloc == STARTITEM) { | |
1008 | safmoae = YES; | |
1009 | } | |
1010 | ||
1011 | /* | |
1012 | * Get out, when, in the normal case, we've hit the second meaningful | |
1013 | * bar; or in the safmoae case, we've skipped back to the back before | |
1014 | * the first bar of the first ending. | |
1015 | */ | |
1016 | } while (! ( (safmoae == NO && barcount == 2) || (safmoae == YES && | |
1017 | (bar_p->endingloc == NOITEM || bar_p->endingloc == ENDITEM)))); | |
1018 | ||
1019 | /* | |
1020 | * Search forward to the next bar, which is the bar before which we | |
1021 | * want to find a GRPSYL. We don't care about pseudobars here. | |
1022 | */ | |
1023 | for (mll_p = mll_p->next; mll_p->str != S_BAR; mll_p = mll_p->next) { | |
1024 | ; | |
1025 | } | |
1026 | ||
1027 | /* | |
1028 | * Now mll_p is the bar before which we want to find the GRPSYL. | |
1029 | * Find the corresponding staff in the previous measure. We do | |
1030 | * this in case the number of staffs changes back and forth; we | |
1031 | * don't want to find the staff in some earlier measure. | |
1032 | */ | |
1033 | ||
1034 | /* search for this staff in previous measure */ | |
1035 | for (*mll_p_p = mll_p->prev; *mll_p_p != (struct MAINLL *) 0 && | |
1036 | (*mll_p_p)->str != S_BAR && | |
1037 | ((*mll_p_p)->str != S_STAFF || | |
1038 | (*mll_p_p)->u.staff_p->staffno != gs_p->staffno); | |
1039 | *mll_p_p = (*mll_p_p)->prev) { | |
1040 | ; | |
1041 | } | |
1042 | ||
1043 | /* if we hit the start or another bar before finding our staff, return*/ | |
1044 | if (*mll_p_p == (struct MAINLL *) 0 || (*mll_p_p)->str == S_BAR) { | |
1045 | return (struct GRPSYL *) 0; | |
1046 | } | |
1047 | ||
1048 | /* return the last GRPSYL of the appropriate voice */ | |
1049 | gs2_p = (*mll_p_p)->u.staff_p->groups_p[ gs_p->vno - 1 ]; | |
1050 | if (gs2_p == (struct GRPSYL *) 0) { | |
1051 | return(gs2_p); | |
1052 | } | |
1053 | while (gs2_p->next != (struct GRPSYL *) 0) { | |
1054 | gs2_p = gs2_p->next; | |
1055 | } | |
1056 | ||
1057 | return (gs2_p); | |
1058 | } | |
1059 | \f | |
1060 | ||
1061 | /* if user asked for octave marks, we need to transpose any affected notes | |
1062 | * by the appropriate number of octaves. This should be called for a measure | |
1063 | * at a time. It will handle all the octave marks | |
1064 | * within the measure for the current voice, both those carrying over into | |
1065 | * this measure and ones starting there. If an octave mark spills beyond | |
1066 | * the end of the measure, the amount to transpose and how long to do so | |
1067 | * is saved away for use in the next measure. Checks for things becoming | |
1068 | * out of range because of the transposition are not done here; caller | |
1069 | * must do that if they care. */ | |
1070 | ||
1071 | void | |
1072 | octave_transpose(staff_p, mll_p, vno, normdir) | |
1073 | ||
1074 | struct STAFF *staff_p; | |
1075 | struct MAINLL *mll_p; /* staff_p connects here, used for bends */ | |
1076 | int vno; /* voice number */ | |
1077 | int normdir; /* YES if should move note pitches up for above and | |
1078 | * down for below. NO if the inverse should be done */ | |
1079 | ||
1080 | { | |
1081 | struct GRPSYL *gs_p; /* walk through list of GRPSYLs */ | |
1082 | struct GRPSYL *gs_roll_p; /* group generated for a roll */ | |
1083 | struct STUFF *stuff_p; /* to look for octave marks */ | |
1084 | RATIONAL total_time; /* accumulated time in measure */ | |
1085 | float float_total_time; /* for comparing with count */ | |
1086 | int carry_adjust; /* adjust to carry into next measure */ | |
1087 | int carry_bars; /* how many bars to carry over */ | |
1088 | float carry_counts; /* how many counts in final bar */ | |
1089 | int staffno; /* which staff we are working with */ | |
1090 | ||
1091 | ||
1092 | staffno = staff_p->staffno; | |
1093 | carry_adjust = carry_bars = 0; | |
1094 | carry_counts = 0.0; | |
1095 | ||
1096 | /* if currently have octave mark */ | |
1097 | if (Octave_adjust[staffno] != 0) { | |
1098 | ||
1099 | /* if bar count > 0, transpose all notes in measure */ | |
1100 | if (--(Octave_bars[staffno]) > 0) { | |
1101 | ||
1102 | for (gs_p = staff_p->groups_p[vno]; | |
1103 | gs_p != (struct GRPSYL *) 0; | |
1104 | gs_p = gs_p->next) { | |
1105 | ||
1106 | grp_octave_adjust(gs_p, Octave_adjust[staffno], mll_p); | |
1107 | } | |
1108 | } | |
1109 | ||
1110 | /* otherwise just transpose until specified time */ | |
1111 | else { | |
1112 | total_time = Zero; | |
1113 | for (gs_p = staff_p->groups_p[vno]; | |
1114 | gs_p != (struct GRPSYL *) 0; | |
1115 | gs_p = gs_p->next) { | |
1116 | ||
1117 | float_total_time = RAT2FLOAT(total_time) | |
1118 | * Score.timeden + 1.0; | |
1119 | ||
1120 | if (float_total_time <= Octave_count[staffno]) { | |
1121 | grp_octave_adjust(gs_p, | |
1122 | Octave_adjust[staffno], mll_p); | |
1123 | } | |
1124 | else { | |
1125 | break; | |
1126 | } | |
1127 | total_time = radd(total_time, gs_p->fulltime); | |
1128 | } | |
1129 | ||
1130 | Octave_adjust[staffno] = 0; | |
1131 | } | |
1132 | } | |
1133 | ||
1134 | /* go through stuff list. If any octave marks, transpose appropriate | |
1135 | * notes in this measure. If extends to next measure, remember for | |
1136 | * next time. If user put in more than one octave | |
1137 | * mark going over the bar, catch that. If there are overlaps within | |
1138 | * a measure, it seems like too much trouble to catch this, so just | |
1139 | * transpose as often as they say and let them figure out why it | |
1140 | * sounds funny. */ | |
1141 | for (stuff_p = staff_p->stuff_p; stuff_p != (struct STUFF *) 0; | |
1142 | stuff_p = stuff_p->next) { | |
1143 | ||
1144 | if (stuff_p->stuff_type == ST_OCTAVE) { | |
1145 | ||
1146 | if (Octave_adjust[staffno] != 0) { | |
1147 | l_warning(stuff_p->inputfile, | |
1148 | stuff_p->inputlineno, | |
1149 | "overlapping octave marks"); | |
1150 | } | |
1151 | ||
1152 | /* figure out how many octaves to move */ | |
1153 | Octave_adjust[staffno] = parse_octave(stuff_p->string, | |
1154 | stuff_p->place, stuff_p->inputfile, | |
1155 | stuff_p->inputlineno); | |
1156 | ||
1157 | /* if this call is for inverse transpostion, adjust | |
1158 | * to go in opposite direction */ | |
1159 | if (normdir == NO) { | |
1160 | Octave_adjust[staffno] *= -1; | |
1161 | } | |
1162 | ||
1163 | /* figure out to which count the octave mark applies | |
1164 | * within this measure. */ | |
1165 | Octave_count[staffno] = (stuff_p->end.bars > 0 ? 1.0 + | |
1166 | RAT2FLOAT(Score.time) * Score.timeden | |
1167 | : stuff_p->end.count); | |
1168 | ||
1169 | total_time = Zero; | |
1170 | for (gs_p = staff_p->groups_p[vno]; | |
1171 | gs_p != (struct GRPSYL *) 0; | |
1172 | gs_p = gs_p->next) { | |
1173 | ||
1174 | float_total_time = RAT2FLOAT(total_time) * | |
1175 | Score.timeden + 1.0; | |
1176 | if (float_total_time >= stuff_p->start.count) { | |
1177 | ||
1178 | if (float_total_time <= | |
1179 | Octave_count[staffno]) { | |
1180 | /* is within the mark, so move */ | |
1181 | grp_octave_adjust(gs_p, | |
1182 | Octave_adjust[staffno], | |
1183 | mll_p); | |
1184 | } | |
1185 | ||
1186 | /* special case. If we have a rolled | |
1187 | * chord, and user specified | |
1188 | * an octave mark without a til clause, | |
1189 | * all the chords that got | |
1190 | * generated internally to cause the | |
1191 | * "roll" effect need to be transposed, | |
1192 | * even though they have been moved | |
1193 | * in time */ | |
1194 | if (float_total_time == stuff_p->start.count | |
1195 | && stuff_p->end.bars == 0 | |
1196 | && stuff_p->end.count == 0.0 | |
1197 | && gs_p->inputlineno < 0) { | |
1198 | ||
1199 | /* adjust all the groups generated | |
1200 | * to create the roll effect */ | |
1201 | for (gs_roll_p = gs_p->next; | |
1202 | gs_roll_p != (struct GRPSYL *) 0; | |
1203 | gs_roll_p = gs_roll_p->next) { | |
1204 | ||
1205 | grp_octave_adjust(gs_roll_p, | |
1206 | Octave_adjust[staffno], | |
1207 | mll_p); | |
1208 | /* stop when we hit the | |
1209 | * end of the roll */ | |
1210 | if (gs_roll_p->inputlineno > 0) { | |
1211 | break; | |
1212 | } | |
1213 | } | |
1214 | } | |
1215 | } | |
1216 | ||
1217 | total_time = radd(total_time, gs_p->fulltime); | |
1218 | } | |
1219 | ||
1220 | /* if octave mark carried over into subsequent | |
1221 | * measure(s), make a note of that for future use */ | |
1222 | if (stuff_p->end.bars > 0) { | |
1223 | if (carry_adjust != 0) { | |
1224 | l_warning(stuff_p->inputfile, | |
1225 | stuff_p->inputlineno, | |
1226 | "overlapping octave marks"); | |
1227 | } | |
1228 | carry_bars = stuff_p->end.bars; | |
1229 | carry_counts = stuff_p->end.count; | |
1230 | carry_adjust = Octave_adjust[staffno]; | |
1231 | } | |
1232 | ||
1233 | Octave_adjust[staffno] = 0; | |
1234 | } | |
1235 | } | |
1236 | ||
1237 | /* above octave marks that were put in on the same input line will | |
1238 | * be in backwards order (because above stuff needs to be that | |
1239 | * way to pile on correctly). However, if the last octave in the | |
1240 | * stuff input line carried over a bar line, we would see it | |
1241 | * first and lose the carryover information when handling the earlier | |
1242 | * octave marks (which are later in the stuff list). That's why the | |
1243 | * carryover information had to be saved. Now we can assign it */ | |
1244 | if (carry_bars > 0) { | |
1245 | Octave_adjust[staffno] = carry_adjust; | |
1246 | Octave_bars[staffno] = carry_bars; | |
1247 | Octave_count[staffno] = carry_counts; | |
1248 | } | |
1249 | } | |
1250 | \f | |
1251 | ||
1252 | /* transpose all the notes in a group by the specified octave adjustment */ | |
1253 | ||
1254 | static void | |
1255 | grp_octave_adjust(gs_p, adj, mll_p) | |
1256 | ||
1257 | struct GRPSYL *gs_p; /* adjust this group */ | |
1258 | int adj; /* add this (potentially negative) value to | |
1259 | * each notelist octave */ | |
1260 | struct MAINLL *mll_p; /* STAFF of gs_p for finding prev grp for bends */ | |
1261 | ||
1262 | { | |
1263 | register int n; | |
1264 | struct GRPSYL *prevgs_p; /* previous group, for bends */ | |
1265 | ||
1266 | for (n = 0; n < gs_p->nnotes; n++) { | |
1267 | gs_p->notelist[n].octave += adj; | |
1268 | } | |
1269 | /* Transpose any bends going to this group */ | |
1270 | prevgs_p = prevgrpsyl(gs_p, &mll_p); | |
1271 | if (prevgs_p == 0) { | |
1272 | /* If there is no previous group, nothing to transpose. */ | |
1273 | return; | |
1274 | } | |
1275 | for (n = 0; n < prevgs_p->nnotes; n++) { | |
1276 | if (prevgs_p->notelist[n].is_bend == YES) { | |
1277 | /* Note that when is_bend is YES, nslurto will always | |
1278 | * be 1, but we loop through as many as there are | |
1279 | * (all 1 of them!), to not be dependent | |
1280 | * on that piece of inside information. | |
1281 | */ | |
1282 | int s; | |
1283 | for (s = 0; s < prevgs_p->notelist[n].nslurto; s++) { | |
1284 | prevgs_p->notelist[n].slurtolist[s].octave += adj; | |
1285 | } | |
1286 | } | |
1287 | } | |
1288 | } | |
1289 | \f | |
1290 | ||
1291 | /* Given a group and note value, return the effective accidental | |
1292 | * on that note, (-2 to +2) taking key signature | |
1293 | * and previous accidentals into account. | |
1294 | * There are certain pathological cases that this doesn't | |
1295 | * handle right, notably if the user changes the key signature at a bar | |
1296 | * line, and the note in question is tied to from before that bar line, | |
1297 | * and the key signature change is such that it changes what the accidental | |
1298 | * should be. But it should handle anything less convoluted than that. | |
1299 | */ | |
1300 | ||
1301 | int | |
1302 | eff_acc(gs_p, note_p, mll_p) | |
1303 | ||
1304 | struct GRPSYL *gs_p; /* get effective accidental for note in this group */ | |
1305 | struct NOTE *note_p; /* get for this note */ | |
1306 | struct MAINLL *mll_p; /* main list item that points to gs_p */ | |
1307 | ||
1308 | { | |
1309 | struct MAINLL *orig_mll_p; | |
1310 | struct GRPSYL *pgs_p; /* previous group */ | |
1311 | int n; | |
1312 | int tie_break; /* YES if there has been a break | |
1313 | * in the chain of notes | |
1314 | * tied together */ | |
1315 | int eff_accidental; /* effective accidental so far */ | |
1316 | ||
1317 | ||
1318 | /* if this group has an explicit accidental, that's also the | |
1319 | * effective accidental */ | |
1320 | if (note_p->accidental != '\0') { | |
1321 | /* note: the - 2 is to adjust for natural being element 2 | |
1322 | * of the Circle array */ | |
1323 | return( (int) (strchr(Acclets, note_p->accidental) - Acclets) - 2); | |
1324 | } | |
1325 | ||
1326 | /* remember which measure we are starting in, so we know when we cross | |
1327 | * a bar line */ | |
1328 | orig_mll_p = mll_p; | |
1329 | ||
1330 | /* init to assume we might have ties */ | |
1331 | tie_break = NO; | |
1332 | ||
1333 | /* if all else fails, we will use the accidental from the key sig */ | |
1334 | eff_accidental = acc_from_keysig(note_p->letter, gs_p->staffno, | |
1335 | mll_p); | |
1336 | ||
1337 | /* back up until we figure out the effective accidental */ | |
1338 | for (pgs_p = prevgrpsyl(gs_p, &mll_p); pgs_p != (struct GRPSYL *) 0; | |
1339 | pgs_p = prevgrpsyl(pgs_p, &mll_p)) { | |
1340 | ||
1341 | ||
1342 | /* see if this group contains the note in question */ | |
1343 | for (n = 0; n < pgs_p->nnotes; n++) { | |
1344 | if (pgs_p->notelist[n].letter == note_p->letter && | |
1345 | pgs_p->notelist[n].octave | |
1346 | == note_p->octave) { | |
1347 | /* it does have the note: it's notelist[n] */ | |
1348 | break; | |
1349 | } | |
1350 | } | |
1351 | ||
1352 | /* see if this is end of ties to the note, working backwards */ | |
1353 | if (n == pgs_p->nnotes) { | |
1354 | /* no note at all, so clearly no tied note */ | |
1355 | tie_break = YES; | |
1356 | } | |
1357 | else if (pgs_p->notelist[n].tie == NO) { | |
1358 | /* end of chain of tied notes */ | |
1359 | tie_break = YES; | |
1360 | } | |
1361 | ||
1362 | if (orig_mll_p == mll_p) { | |
1363 | /* we're still in same measure. If we have a matching | |
1364 | * note, see if it has an accidental */ | |
1365 | if (n < pgs_p->nnotes) { | |
1366 | if (pgs_p->notelist[n].accidental != '\0') { | |
1367 | return( (int) (strchr(Acclets, | |
1368 | pgs_p->notelist[n].accidental) | |
1369 | - Acclets) - 2); | |
1370 | } | |
1371 | } | |
1372 | ||
1373 | /* have to keep backing up */ | |
1374 | } | |
1375 | else { | |
1376 | /* Now in previous measure. If no matching note, | |
1377 | * we use the effective accidental found so far */ | |
1378 | if (n == pgs_p->nnotes) { | |
1379 | return(eff_accidental); | |
1380 | } | |
1381 | ||
1382 | /* if the note isn't tied, then use the most recent | |
1383 | * effective accidental we found */ | |
1384 | if (pgs_p->notelist[n].tie == NO || tie_break == YES) { | |
1385 | return(eff_accidental); | |
1386 | } | |
1387 | ||
1388 | /* if there is an accidental on this note, | |
1389 | * then it's the one we're looking for. */ | |
1390 | if (pgs_p->notelist[n].accidental != '\0') { | |
1391 | return( (int) (strchr(Acclets, | |
1392 | pgs_p->notelist[n].accidental) - | |
1393 | Acclets - 2)); | |
1394 | } | |
1395 | ||
1396 | /* need to continue working backwards toward | |
1397 | * the beginning of this new measure */ | |
1398 | orig_mll_p = mll_p; | |
1399 | eff_accidental = acc_from_keysig(note_p->letter, | |
1400 | gs_p->staffno, mll_p); | |
1401 | } | |
1402 | } | |
1403 | ||
1404 | /* backed up all the way to the beginning of the song, use last we | |
1405 | * found */ | |
1406 | return(eff_accidental); | |
1407 | } | |
1408 | \f | |
1409 | ||
1410 | /* given a letter and staff number, return 1 if the pitch with that letter | |
1411 | * gets a sharps according to the key signature, or -1 if it gets a flat, | |
1412 | * or 0 if it gets neither. */ | |
1413 | ||
1414 | int | |
1415 | acc_from_keysig(letter, staffno, mll_p) | |
1416 | ||
1417 | int letter; /* which pitch */ | |
1418 | int staffno; /* which staff to get the key signature from */ | |
1419 | struct MAINLL *mll_p; /* pitch is from the staff hanging off of here */ | |
1420 | ||
1421 | { | |
1422 | int index; /* where the letter is in circle of fifths */ | |
1423 | int sharps; /* sharps in key sig for the given staff */ | |
1424 | struct SSV *ssv_p; /* to get key signature */ | |
1425 | ||
1426 | ||
1427 | /* find letter in circle of fifths */ | |
1428 | index = strchr(Circle, letter) - Circle + 1; | |
1429 | ||
1430 | /* get key signature. Unfortunately, the SSVs may not be | |
1431 | * accurate at the time we are called, so we have to search | |
1432 | * backwards in the main list for the most recent relevant | |
1433 | * key signature change. */ | |
1434 | for (sharps = 0; mll_p != (struct MAINLL *) 0; mll_p = mll_p->prev) { | |
1435 | if (mll_p->str == S_SSV) { | |
1436 | ssv_p = mll_p->u.ssv_p; | |
1437 | ||
1438 | /* does this SSV have a key signature change in it? */ | |
1439 | if (ssv_p->used[SHARPS] == YES) { | |
1440 | if (ssv_p->context == C_STAFF && | |
1441 | ssv_p->staffno == staffno) { | |
1442 | /* aha! found the most recent | |
1443 | * key signature | |
1444 | * for the relevant staff */ | |
1445 | sharps = ssv_p->sharps; | |
1446 | break; | |
1447 | } | |
1448 | else if (ssv_p->context == C_SCORE) { | |
1449 | /* this will be the score-wide default | |
1450 | * if we don't find a staff-specific | |
1451 | * value, so save this as our default */ | |
1452 | sharps = ssv_p->sharps; | |
1453 | } | |
1454 | } | |
1455 | } | |
1456 | } | |
1457 | ||
1458 | if (sharps > 0) { | |
1459 | /* key signature is one with sharps */ | |
1460 | if (index <= sharps) { | |
1461 | /* this letter gets a sharp */ | |
1462 | return(1); | |
1463 | } | |
1464 | } | |
1465 | else if (sharps < 0) { | |
1466 | /* key signature is one with flats */ | |
1467 | if ( (8 - index) <= -sharps) { | |
1468 | /* this letter gets a flat */ | |
1469 | return(-1); | |
1470 | } | |
1471 | } | |
1472 | ||
1473 | /* must be a natural */ | |
1474 | return(0); | |
1475 | } | |
1476 | ||
1477 | /* Set Staffscale, Stepsize, Stdpad, and other similar values based on the | |
1478 | * specified staff number. If staff of 0 is given, set Staffscale to the | |
1479 | * score value | |
1480 | */ | |
1481 | ||
1482 | void | |
1483 | set_staffscale(s) | |
1484 | ||
1485 | int s; /* which staff */ | |
1486 | ||
1487 | { | |
1488 | Staffscale = (s == 0 ? Score.staffscale | |
1489 | : svpath(s, STAFFSCALE)->staffscale); | |
1490 | Stepsize = STEPSIZE * Staffscale; | |
1491 | Stdpad = STDPAD * Staffscale; | |
1492 | Flagsep = FLAGSEP * Staffscale; | |
1493 | Smflagsep = SMFLAGSEP * Staffscale; | |
1494 | Tupheight = TUPHEIGHT * Staffscale; | |
1495 | } | |
1496 | \f | |
1497 | ||
1498 | /* Determine the space between lines of a grid. A staff of 0 means use | |
1499 | * the score size. A staff of -1 means ATEND. Return distance in inches. */ | |
1500 | ||
1501 | double | |
1502 | gridspace(staff) | |
1503 | ||
1504 | int staff; | |
1505 | ||
1506 | { | |
1507 | double space; | |
1508 | ||
1509 | if (staff == -1) { | |
1510 | space = ATEND_GS * STEPSIZE * Score.gridscale; | |
1511 | } | |
1512 | else { | |
1513 | space = WHEREUSED_GS * STEPSIZE | |
1514 | * svpath(staff, STAFFSCALE)->staffscale | |
1515 | * svpath(staff, GRIDSCALE)->gridscale; | |
1516 | } | |
1517 | return(space); | |
1518 | } | |
1519 | \f | |
1520 | ||
1521 | /* Given a grid, return (via pointer) the items needed for the PostScript | |
1522 | * plus the top fret. | |
1523 | */ | |
1524 | ||
1525 | void | |
1526 | gridinfo(grid_p, staff, frets_p, fretnum_p, numvert_p, topfret_p) | |
1527 | ||
1528 | struct GRID *grid_p; | |
1529 | int staff; /* 0 == score, -1 = ATEND, otherwise the staff number */ | |
1530 | int *frets_p; /* how many frets high the grid should be */ | |
1531 | int *fretnum_p; /* the N of "N fr" */ | |
1532 | int *numvert_p; /* how many frets from the top to print the "N fr" */ | |
1533 | int *topfret_p; /* the fret number of the top line of the grid */ | |
1534 | ||
1535 | { | |
1536 | int minfret, maxfret; /* smallest and largest frets used */ | |
1537 | int rightmost_fret; /* the 'N' of 'N fr" if any */ | |
1538 | int right_stringnum; /* string number having rightmost_fret */ | |
1539 | int mincurvefret; /* smallest fret number inside curve */ | |
1540 | int has_o; /* if there are 'o' items */ | |
1541 | int gridfret; | |
1542 | int s; | |
1543 | ||
1544 | ||
1545 | /* Go through strings finding min/max/rightmost */ | |
1546 | minfret = MAXFRET + 1; | |
1547 | maxfret = MINFRET - 1; | |
1548 | mincurvefret = MAXFRET + 1; | |
1549 | has_o = NO; | |
1550 | rightmost_fret = right_stringnum = 0; /* avoids bogus warnings */ | |
1551 | for (s = 0; s < grid_p->numstr; s++) { | |
1552 | /* x o and - things don't count */ | |
1553 | if (grid_p->positions[s] > 0) { | |
1554 | if (grid_p->positions[s] < minfret) { | |
1555 | minfret = grid_p->positions[s]; | |
1556 | } | |
1557 | if (grid_p->positions[s] > maxfret) { | |
1558 | maxfret = grid_p->positions[s]; | |
1559 | } | |
1560 | rightmost_fret = grid_p->positions[s]; | |
1561 | right_stringnum = s; | |
1562 | ||
1563 | /* find smallest fret inside curve */ | |
1564 | if (grid_p->curvel != 0 && s >= grid_p->curvel - 1 && | |
1565 | s <= grid_p->curver - 1 && | |
1566 | grid_p->positions[s] < mincurvefret) { | |
1567 | mincurvefret = grid_p->positions[s]; | |
1568 | } | |
1569 | } | |
1570 | else if (grid_p->positions[s] == 0) { | |
1571 | has_o = YES; | |
1572 | } | |
1573 | } | |
1574 | ||
1575 | /* set the values to defaults, then calculate actuals if needed */ | |
1576 | *frets_p = 5; | |
1577 | *fretnum_p = 0; | |
1578 | *numvert_p = 0; | |
1579 | if (minfret <= MAXFRET) { | |
1580 | /* at least one fret was used */ | |
1581 | ||
1582 | /* figure out how many frets tall to make the grid */ | |
1583 | *frets_p = maxfret + 1; | |
1584 | ||
1585 | /* see if gridfret is set */ | |
1586 | gridfret = svpath(staff == -1 ? 0 : staff, GRIDFRET)->gridfret; | |
1587 | if (gridfret != NOGRIDFRET) { | |
1588 | /* gridfret is set; see if all frets larger than that. | |
1589 | * But we only use "N fr" if there are no 'o' items. */ | |
1590 | if (has_o == NO && minfret >= gridfret) { | |
1591 | /* We will need "N fr" | |
1592 | * Usually we use the rightmost string | |
1593 | * that has a fret on it, | |
1594 | * but there is one special case: | |
1595 | * if the curve comes at least that far right, | |
1596 | * and the minimum fret inside the curve is | |
1597 | * smaller than the rightmost_fret, then we | |
1598 | * put the "N fr" by the curve minimum. | |
1599 | */ | |
1600 | if (grid_p->curver - 1 >= right_stringnum | |
1601 | && mincurvefret < rightmost_fret) { | |
1602 | rightmost_fret = mincurvefret; | |
1603 | } | |
1604 | *fretnum_p = rightmost_fret; | |
1605 | *numvert_p = rightmost_fret - minfret + 1; | |
1606 | *frets_p = maxfret - minfret + 2; | |
1607 | } | |
1608 | } | |
1609 | ||
1610 | if (*frets_p < 5) { | |
1611 | /* always at least 4 frets plus top line */ | |
1612 | *frets_p = 5; | |
1613 | } | |
1614 | } | |
1615 | *topfret_p = (*fretnum_p == 0 ? 0 : *fretnum_p - *numvert_p); | |
1616 | } | |
1617 | \f | |
1618 | ||
1619 | /* Determine the dimensions of a grid, relative to a point in the middle | |
1620 | * of the top line of the grid, and return them via pointers. | |
1621 | * If pointers are 0, don't bother; caller doesn't care about these things. | |
1622 | * Things in this function must be kept in sync with the PostScript prolog | |
1623 | * definition of grids. | |
1624 | */ | |
1625 | ||
1626 | void | |
1627 | gridsize(grid_p, staff, north_p, south_p, east_p, west_p) | |
1628 | ||
1629 | struct GRID *grid_p; /* find the size of this grid */ | |
1630 | int staff; /* use this staff for scaling. 0 means score, | |
1631 | * -1 means ATEND */ | |
1632 | float *north_p; /* return values... */ | |
1633 | float *south_p; | |
1634 | float *east_p; | |
1635 | float *west_p; | |
1636 | ||
1637 | { | |
1638 | double space; /* distance between adjacent line of the grid */ | |
1639 | int frets; | |
1640 | int fretnum; | |
1641 | int numvert; | |
1642 | int topfret; | |
1643 | int s; /* string index */ | |
1644 | ||
1645 | if (grid_p == 0) { | |
1646 | pfatal("gridsize() was passed a null pointer"); | |
1647 | } | |
1648 | ||
1649 | /* determine distance between grid lines and other needed info */ | |
1650 | space = gridspace(staff); | |
1651 | gridinfo(grid_p, staff, &frets, &fretnum, &numvert, &topfret); | |
1652 | ||
1653 | /* Start with minimum. East and west are equal, at half the | |
1654 | * total grid width, based on number of strings. The number of | |
1655 | * spaces is the number of strings minus one, but dots, X's, | |
1656 | * and O's will hang over the sides, so use the number of strings. | |
1657 | * Then adjust east for "N fr" if needed. */ | |
1658 | if (west_p != 0) { | |
1659 | *west_p = -((space * grid_p->numstr) / 2.0); | |
1660 | } | |
1661 | if (east_p != 0) { | |
1662 | *east_p = (space * grid_p->numstr) / 2.0; | |
1663 | if (fretnum > 0) { | |
1664 | /* We will need "N fr". | |
1665 | * Get enough space to hold | |
1666 | * font, size, 2 digits, space, "fr", null */ | |
1667 | char tmp[8]; | |
1668 | ||
1669 | /* this is printed in Palatino Roman */ | |
1670 | tmp[0] = (char) FONT_PR; | |
1671 | ||
1672 | /* Between staffscale and gridscale, | |
1673 | * we could get a size that we can't represent | |
1674 | * in internal format, so get string width | |
1675 | * in default size and adjust afterwards. */ | |
1676 | tmp[1] = (char) DFLT_SIZE; | |
1677 | ||
1678 | /* since we know there are no funny characters | |
1679 | * in this string, we can cheat and not bother | |
1680 | * to call the string normalizer. */ | |
1681 | sprintf(tmp + 2, "%d fr", fretnum); | |
1682 | ||
1683 | *east_p += strwidth(tmp) * | |
1684 | (space * PPI * 1.9)/ DFLT_SIZE; | |
1685 | } | |
1686 | } | |
1687 | ||
1688 | if (north_p != 0) { | |
1689 | /* Always put almost one space of padding on top, which allows | |
1690 | * room for x's and o's and curves. Even if this particular grid | |
1691 | * doesn't have those, many do, so it's nice to line | |
1692 | * all of them up as much as possible */ | |
1693 | *north_p = 0.85 * space; | |
1694 | /* If there is a curve above the top fret, | |
1695 | * with x's or o's above it, leave some more space */ | |
1696 | if (grid_p->positions[grid_p->curvel - 1] == topfret + 1 | |
1697 | || grid_p->positions[grid_p->curver - 1] | |
1698 | == topfret + 1) { | |
1699 | for (s = grid_p->curvel; s <= grid_p->curver; s++) { | |
1700 | if (grid_p->positions[s-1] == 0 || | |
1701 | grid_p->positions[s-1] | |
1702 | == -1) { | |
1703 | *north_p += 0.7 * space; | |
1704 | break; | |
1705 | } | |
1706 | } | |
1707 | } | |
1708 | } | |
1709 | ||
1710 | /* Grid is always at least 4 boxes high, more if needed, | |
1711 | * plus 1/2 space of padding at bottom */ | |
1712 | if (south_p != 0) { | |
1713 | *south_p = -(frets - 0.5) * space; | |
1714 | } | |
1715 | } | |
1716 | \f | |
1717 | ||
1718 | /* This function returns the minimum distance needed between the current | |
1719 | * staff and previous one, given their clefs and allowing for a measure | |
1720 | * number. The clefs might be NOCLEF, like if this is for the top | |
1721 | * staff of a page or a staff where printclef is false. | |
1722 | */ | |
1723 | ||
1724 | double | |
1725 | clefspace(prevclef, prevscale, curclef, curscale, measnum) | |
1726 | ||
1727 | int prevclef; /* clef on staff above */ | |
1728 | double prevscale; /* staffscale for the staff above */ | |
1729 | int curclef; /* clef on staff below */ | |
1730 | double curscale; /* staffscale for the staff below */ | |
1731 | int measnum; /* YES if a measure number needs to be printed */ | |
1732 | ||
1733 | { | |
1734 | double cur_extend; /* space needed for current clef */ | |
1735 | double prev_extend; /* space needed for clef above */ | |
1736 | double space_needed; /* total for both clefs and measure number */ | |
1737 | ||
1738 | ||
1739 | /* Figure out how much the clef on current staff sticks up, | |
1740 | * Do in approximate STEPSIZEs here, and adjust later for scale. */ | |
1741 | switch (curclef) { | |
1742 | case TREBLE_8A: | |
1743 | cur_extend = 6.0; | |
1744 | break; | |
1745 | case TREBLE: | |
1746 | case TREBLE_8: | |
1747 | cur_extend = 4.0; | |
1748 | break; | |
1749 | case BARITONE: | |
1750 | cur_extend = 4.2; | |
1751 | break; | |
1752 | case TENOR: | |
1753 | cur_extend = 2.2; | |
1754 | break; | |
1755 | case FRENCHVIOLIN: | |
1756 | cur_extend = 2.0; | |
1757 | break; | |
1758 | default: | |
1759 | cur_extend = 0.0; | |
1760 | break; | |
1761 | } | |
1762 | ||
1763 | /* Similar for the clef above, only how much it sticks down | |
1764 | * rather than up */ | |
1765 | switch (prevclef) { | |
1766 | case TREBLE: | |
1767 | case TREBLE_8A: | |
1768 | prev_extend = 3.2; | |
1769 | break; | |
1770 | case MEZZOSOPRANO: | |
1771 | prev_extend = 2.2; | |
1772 | break; | |
1773 | case SOPRANO: | |
1774 | prev_extend = 4.2; | |
1775 | break; | |
1776 | case FRENCHVIOLIN: | |
1777 | case TREBLE_8: | |
1778 | prev_extend = 5.2; | |
1779 | break; | |
1780 | default: | |
1781 | prev_extend = 0.0; | |
1782 | break; | |
1783 | } | |
1784 | ||
1785 | /* Add top and bottom together, adjusting for scale factors, | |
1786 | * and adding a little padding */ | |
1787 | space_needed = prev_extend * STEPSIZE * prevscale + | |
1788 | cur_extend * STEPSIZE * curscale + | |
1789 | STDPAD * curscale; | |
1790 | ||
1791 | /* Add on the space for the measure number, if necessary. | |
1792 | * Note that we can use fontascent since all digits are that high. */ | |
1793 | if (measnum == YES) { | |
1794 | space_needed += fontascent(Score.measnumfamily + Score.measnumfont, | |
1795 | Score.measnumsize) + STDPAD; | |
1796 | } | |
1797 | return(space_needed); | |
1798 | } | |
1799 | \f | |
1800 | /* | |
1801 | * Name: eff_rightmargin() | |
1802 | * | |
1803 | * Abstract: Return the effective right margin for this score. | |
1804 | * | |
1805 | * Returns: the margin in inches | |
1806 | * | |
1807 | * Description: There are two reason that code can't just use Score.rightmargin | |
1808 | * but must call this function. First, the way the "scale" param | |
1809 | * works, we pretend the paper is smaller by that amount and then | |
1810 | * in PostScript magnify it back to the real size; but margins are | |
1811 | * not to be scaled, so we have to fake out the code by dividing | |
1812 | * out the scale here. Second, the user can override the param | |
1813 | * on a "newscore" or "newpage". To ignore a user override, pass | |
1814 | * 0 for mainll_p, else pass some MLL on that score. | |
1815 | */ | |
1816 | ||
1817 | double | |
1818 | eff_rightmargin(mainll_p) | |
1819 | ||
1820 | struct MAINLL *mainll_p; /* MLL struct on some score, or 0 for normal margin */ | |
1821 | ||
1822 | { | |
1823 | /* if not already at a FEED, find FEED at right end of this score */ | |
1824 | while (mainll_p != 0 && mainll_p->str != S_FEED) | |
1825 | mainll_p = mainll_p->next; | |
1826 | ||
1827 | /* if there is none, or there is no override, use the parameter */ | |
1828 | if (mainll_p == 0 || mainll_p->u.feed_p->rightmargin < 0.0) | |
1829 | return (Score.rightmargin / Score.scale_factor); | |
1830 | ||
1831 | /* use this override value */ | |
1832 | return (mainll_p->u.feed_p->rightmargin / Score.scale_factor); | |
1833 | } | |
1834 | \f | |
1835 | /* | |
1836 | * Name: eff_leftmargin() | |
1837 | * | |
1838 | * Abstract: Return the effective left margin for this score. | |
1839 | * | |
1840 | * Returns: the margin in inches | |
1841 | * | |
1842 | * Description: There are two reason that code can't just use Score.leftmargin | |
1843 | * but must call this function. First, the way the "scale" param | |
1844 | * works, we pretend the paper is smaller by that amount and then | |
1845 | * in PostScript magnify it back to the real size; but margins are | |
1846 | * not to be scaled, so we have to fake out the code by dividing | |
1847 | * out the scale here. Second, the user can override the param | |
1848 | * on a "newscore" or "newpage". To ignore a user override, pass | |
1849 | * 0 for mainll_p, else pass some MLL on that score. | |
1850 | */ | |
1851 | ||
1852 | double | |
1853 | eff_leftmargin(mainll_p) | |
1854 | ||
1855 | struct MAINLL *mainll_p; /* MLL struct on some score, or 0 for normal margin */ | |
1856 | ||
1857 | { | |
1858 | /* if not already at a FEED, find FEED at left end of this score */ | |
1859 | while (mainll_p != 0 && mainll_p->str != S_FEED) | |
1860 | mainll_p = mainll_p->prev; | |
1861 | ||
1862 | /* if there is none, or there is no override, use the parameter */ | |
1863 | if (mainll_p == 0 || mainll_p->u.feed_p->leftmargin < 0.0) | |
1864 | return (Score.leftmargin / Score.scale_factor); | |
1865 | ||
1866 | /* use this override value */ | |
1867 | return (mainll_p->u.feed_p->leftmargin / Score.scale_factor); | |
1868 | } | |
1869 | \f | |
1870 | /* | |
1871 | * Name: findprimes() | |
1872 | * | |
1873 | * Abstract: Find all the prime numbers up to the given number ("max"). | |
1874 | * | |
1875 | * Returns: array indexed 0 to max, each element YES or NO (is index prime?) | |
1876 | * | |
1877 | * Description: This function mallocs and returns an array of shorts, indexed | |
1878 | * from 0 to max. Each element is YES or NO, telling whether its | |
1879 | * index is a prime number. The first time it is called, or if | |
1880 | * max is greater than the previous time, it calculates all this, | |
1881 | * but on other calls it just returns the answer from before. | |
1882 | */ | |
1883 | ||
1884 | short * | |
1885 | findprimes(max) | |
1886 | ||
1887 | int max; /* max integer we need to consider */ | |
1888 | ||
1889 | { | |
1890 | static short *isprime = 0; /* array to be malloc'ed */ | |
1891 | static int oldmax = 0; /* the max passed in previously */ | |
1892 | int stop; /* where to stop looking */ | |
1893 | int prime; /* a prime number */ | |
1894 | int n; /* loop index */ | |
1895 | ||
1896 | ||
1897 | /* if we've already been here ... */ | |
1898 | if (isprime != 0) { | |
1899 | /* if we've already done the same or more, just return answer*/ | |
1900 | if (max <= oldmax) { | |
1901 | return (isprime); | |
1902 | } | |
1903 | /* max increased; free the old array */ | |
1904 | FREE(isprime); | |
1905 | } | |
1906 | oldmax = max; /* remember if for next time */ | |
1907 | ||
1908 | MALLOCA(short, isprime, max + 1); | |
1909 | ||
1910 | /* 0 and 1 are not primes */ | |
1911 | isprime[0] = isprime[1] = NO; | |
1912 | ||
1913 | /* | |
1914 | * We're going to use the Sieve of Eristosthenes. We start out by | |
1915 | * assuming everything 2 and greater is prime. | |
1916 | */ | |
1917 | for (n = 2; n <= max; n++) { | |
1918 | isprime[n] = YES; | |
1919 | } | |
1920 | ||
1921 | /* the following loop can stop when it gets to this point */ | |
1922 | stop = sqrt((double)max) + 1; | |
1923 | ||
1924 | prime = 2; | |
1925 | while (prime <= stop) { | |
1926 | /* knock out all multiples of this prime number */ | |
1927 | for (n = 2 * prime; n <= max; n += prime) { | |
1928 | isprime[n] = NO; | |
1929 | } | |
1930 | /* find the next prime */ | |
1931 | for (n = prime + 1; n <= stop && isprime[n] == NO; n++) | |
1932 | ; | |
1933 | prime = n; | |
1934 | } | |
1935 | ||
1936 | return (isprime); | |
1937 | } | |
1938 | \f | |
1939 | /* | |
1940 | * Name: factor() | |
1941 | * | |
1942 | * Abstract: Factor the given number. | |
1943 | * | |
1944 | * Returns: array indexed 0 to num, giving the prime factors | |
1945 | * | |
1946 | * Description: This function mallocs and returns an array of shorts, indexed | |
1947 | * from 0 to max. Each element indexed by a prime number tells | |
1948 | * how many times that prime factor occurs in num. All other | |
1949 | * elements are 0. The first time it is called, or if num is | |
1950 | * different from the previous time, it calculates all this, | |
1951 | * but on other calls it just returns the answer from before. | |
1952 | */ | |
1953 | ||
1954 | short * | |
1955 | factor(num) | |
1956 | ||
1957 | int num; /* the integer to be factored */ | |
1958 | ||
1959 | { | |
1960 | static short *factors = 0; /* array to be malloc'ed */ | |
1961 | static int oldnum = 0; /* the number passed in previously */ | |
1962 | short *isprime; /* list of which numbers are prime */ | |
1963 | int orignum; /* remember original num */ | |
1964 | int n; /* loop index */ | |
1965 | ||
1966 | ||
1967 | /* if we've just done the same number, just return the answer */ | |
1968 | if (factors != 0) { | |
1969 | /* if we've already done the same or more, just return answer*/ | |
1970 | if (num == oldnum) { | |
1971 | return (factors); | |
1972 | } | |
1973 | /* num changed; free the old array */ | |
1974 | FREE(factors); | |
1975 | } | |
1976 | oldnum = num; /* remember it for next time */ | |
1977 | ||
1978 | CALLOCA(short, factors, num + 1); | |
1979 | ||
1980 | /* find which numbers up to num are primes */ | |
1981 | isprime = findprimes(num); | |
1982 | ||
1983 | /* | |
1984 | * For every prime number until "num" is used up, divide it into num | |
1985 | * as many times as possible, keeping track of how many times. | |
1986 | */ | |
1987 | orignum = num; | |
1988 | for (n = 2; n <= orignum && num > 1; n++) { | |
1989 | if (isprime[n] == YES) { | |
1990 | while (num % n == 0) { | |
1991 | num /= n; | |
1992 | factors[n]++; | |
1993 | } | |
1994 | } | |
1995 | } | |
1996 | ||
1997 | return (factors); | |
1998 | } | |
1999 | \f | |
2000 | ||
2001 | /* Return the width of the widest note head in the given GRPSYL. */ | |
2002 | ||
2003 | double | |
2004 | widest_head(gs_p) | |
2005 | ||
2006 | struct GRPSYL *gs_p; | |
2007 | ||
2008 | { | |
2009 | double widest; /* widest note head in the group */ | |
2010 | double thiswidth; /* width of current note */ | |
2011 | int n; /* note index */ | |
2012 | ||
2013 | widest = 0.0; | |
2014 | for (n = 0; n < gs_p->nnotes; n++) { | |
2015 | thiswidth = width(gs_p->notelist[n].headfont, | |
2016 | (gs_p->notelist[n].notesize == GS_NORMAL ? | |
2017 | DFLT_SIZE : SMALLSIZE), | |
2018 | gs_p->notelist[n].headchar); | |
2019 | if (thiswidth > widest) { | |
2020 | widest = thiswidth; | |
2021 | } | |
2022 | } | |
2023 | return(widest); | |
2024 | } |