chiark / gitweb /
Merge branch 'arkkra' into shiny
[mup] / mup / mup / utils.c
CommitLineData
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
12static void grp_octave_adjust P((struct GRPSYL *gs_p, int adj, struct MAINLL *mll_p));
13static void set_height_blockhead P((struct BLOCKHEAD *blockhead_p, int context,
14 struct MAINLL *mll_p));
15static double coord_staffscale P((float *coord_array));
16
17\f
18
19/* set _cur location variable to specified value */
20
21void
22set_cur(x, y)
23
24float 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
40void
41set_win(n, s, e, w)
42
43float 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
66double
67width_barline(bar_p)
68
69struct 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
119double
120eos_bar_adjust(bar_p)
121
122struct 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
146double
147width_clefsig(clefsig_p)
148
149struct 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
160int
161clefchar(clef)
162
163int 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
192double
193clefwidth(clef, is_small)
194
195int clef; /* TREBLE, BASS, ALTO, FRENCHVIOLIN, etc */
196int 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
215int
216clefvert(clef, is_small, north_p, south_p)
217
218int clef; /* TREBLE, BASS, ALTO, FRENCHVIOLIN, etc */
219int 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. */
222float *north_p; /* if non-null, relative north will be returned here */
223float *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
312static void
313set_height_blockhead(blockhead_p, context, mll_p)
314
315struct BLOCKHEAD *blockhead_p; /* which block to get height of */
316int context; /* C_HEADER, etc */
317struct 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
461void
462calc_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
537int
538numbeams(btime)
539
540int 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
565int acc2char(acc)
566
567int 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
594double
595inpc_x(inpcoord_p, fname, lineno)
596
597struct INPCOORD *inpcoord_p; /* return the x value of this inpcoord */
598char *fname; /* filename, for error message */
599int 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
637double
638inpc_y(inpcoord_p, fname, lineno)
639
640struct INPCOORD *inpcoord_p; /* return y value of this inpcoord */
641char *fname; /* filename, for error message */
642int 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
676static double
677coord_staffscale(coord_array)
678
679float *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
701double
702find_y_stem(gs_p)
703
704struct 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
729double
730find_x_stem(gs_p)
731
732struct 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
759double
760width_keysig(sharps, naturals)
761
762int sharps; /* how many sharps to print, or if negative, how many flats. */
763int 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
807struct GRPSYL *
808nextgrpsyl(gs_p, mll_p_p)
809
810struct GRPSYL *gs_p; /* the given GRPSYL */
811struct 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
912struct GRPSYL *
913prevgrpsyl(gs_p, mll_p_p)
914
915struct GRPSYL *gs_p; /* the given GRPSYL */
916struct 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
1071void
1072octave_transpose(staff_p, mll_p, vno, normdir)
1073
1074struct STAFF *staff_p;
1075struct MAINLL *mll_p; /* staff_p connects here, used for bends */
1076int vno; /* voice number */
1077int 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
1254static void
1255grp_octave_adjust(gs_p, adj, mll_p)
1256
1257struct GRPSYL *gs_p; /* adjust this group */
1258int adj; /* add this (potentially negative) value to
1259 * each notelist octave */
1260struct 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
1301int
1302eff_acc(gs_p, note_p, mll_p)
1303
1304struct GRPSYL *gs_p; /* get effective accidental for note in this group */
1305struct NOTE *note_p; /* get for this note */
1306struct 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
1414int
1415acc_from_keysig(letter, staffno, mll_p)
1416
1417int letter; /* which pitch */
1418int staffno; /* which staff to get the key signature from */
1419struct 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
1482void
1483set_staffscale(s)
1484
1485int 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
1501double
1502gridspace(staff)
1503
1504int 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
1525void
1526gridinfo(grid_p, staff, frets_p, fretnum_p, numvert_p, topfret_p)
1527
1528struct GRID *grid_p;
1529int staff; /* 0 == score, -1 = ATEND, otherwise the staff number */
1530int *frets_p; /* how many frets high the grid should be */
1531int *fretnum_p; /* the N of "N fr" */
1532int *numvert_p; /* how many frets from the top to print the "N fr" */
1533int *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
1626void
1627gridsize(grid_p, staff, north_p, south_p, east_p, west_p)
1628
1629struct GRID *grid_p; /* find the size of this grid */
1630int staff; /* use this staff for scaling. 0 means score,
1631 * -1 means ATEND */
1632float *north_p; /* return values... */
1633float *south_p;
1634float *east_p;
1635float *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
1724double
1725clefspace(prevclef, prevscale, curclef, curscale, measnum)
1726
1727int prevclef; /* clef on staff above */
1728double prevscale; /* staffscale for the staff above */
1729int curclef; /* clef on staff below */
1730double curscale; /* staffscale for the staff below */
1731int 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
1817double
1818eff_rightmargin(mainll_p)
1819
1820struct 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
1852double
1853eff_leftmargin(mainll_p)
1854
1855struct 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
1884short *
1885findprimes(max)
1886
1887int 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
1954short *
1955factor(num)
1956
1957int 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
2003double
2004widest_head(gs_p)
2005
2006struct 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}