1 /* Copyright (c) 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005 by Arkkra Enterprises */
2 /* All rights reserved */
6 * Description: This file contains functions for setting all remaining
7 * relative vertical coordinates.
15 /* how many rectangles to malloc initially and at each realloc if needed */
16 #define RECTCHUNK (100)
18 /* rectangle structure; see procscore() prologue for explanation of its use */
20 float n, s, e, w; /* boundaries of a rectangle */
21 /* horz coords are absolute; vertical coords */
22 /* are relative to center staff line */
23 /* (baseline for "between") */
24 short relevant; /* is rectangle relevant? */
25 short tried; /* have we tried this one yet? */
27 static struct RECTAB *rectab; /* ptr to malloc'ed and realloc'ed array */
29 /* this fudge factor prevents roundoff error from causing overlap */
32 /* these symbols tell certain subroutines which things to work on */
33 #define DO_OTHERS 0 /* default */
37 static int reclim; /* index after last rectangle in rectab */
39 static void procstaff P((struct MAINLL *mainll_p, int s));
40 static void dostaff P((int s, int place));
41 static void dogroups P((struct MAINLL *start_p, int s, int place));
42 static void llgrps P((struct STAFF *staff_p, struct GRPSYL *gs_p, int place));
43 static void dobeamalt P((struct MAINLL *start_p, int s, int place));
44 static void onebeamalt P((struct GRPSYL *gs_p));
45 static double getstemendvert P((struct GRPSYL *gs_p));
46 static void linerects P((double x1, double y1, double x2, double y2, int side,
48 static void docurve P((struct MAINLL *start_p, int s, int place,
50 static void curverect P((int s, struct STUFF *stuff_p, double halfstaff));
51 static void curvepiecerect P((double x1, double y1, double x2, double y2,
53 static void dotuplet P((struct MAINLL *start_p, int s, int place));
54 static void onetuplet P((struct STAFF *staff_p, struct GRPSYL *start_p,
56 static void domiscstuff P((struct MAINLL *start_p, int s, int place,
57 unsigned long do_which));
58 static void dolyrics P((struct MAINLL *start_p, int s, int place));
59 static void getvsize P((struct MAINLL *start_p, int s, int place, int v,
60 float *asc_p, float *des_p));
61 static void setsylvert P((struct MAINLL *start_p, int s, int place, int v,
63 static void dopedal P((struct MAINLL *start_p, int s));
64 static void doendings P((struct MAINLL *start_p, int s));
65 static void storeend P((struct MAINLL *start_p, struct MAINLL *end_p, int s));
66 static void dorehears P((struct MAINLL *start_p, int s));
67 static double stackit P((double west, double east, double height, double dist,
69 static void inc_reclim P((void));
74 * Abstract: Set all relative vertical coords not already set.
78 * Description: This function sets all remaining relative vertical coords.
79 * It calls procstaff() once for each staff in each score to
87 struct MAINLL *mainll_p; /* point along main linked list */
88 struct MAINLL *end_p; /* point at end of a piece of MLL */
89 struct MAINLL *m2_p; /* another pointer along MLL */
90 int s; /* staff number */
91 int gotbar; /* was a bar found in this chunk? */
96 * Find each section of the main linked list, delimited by FEEDs.
97 * For each such section, call procstaff() for each visible staff.
98 * Keep SSVs up to date so that we always know what staffs are visible.
100 initstructs(); /* clean out old SSV info */
102 /* skip anything before first FEED first */
103 for (mainll_p = Mainllhc_p; mainll_p->str != S_FEED;
104 mainll_p = mainll_p->next) {
105 if (mainll_p->str == S_SSV)
106 asgnssv(mainll_p->u.ssv_p);
110 * Initially allocate RECTCHUNK rectangles. If we find we need more at
111 * some point, we'll realloc to get more.
113 MALLOC(RECTAB, rectab, RECTCHUNK);
117 * Find end of this chunk. If it has no bars in it, this must
118 * either be the end of the MLL and there was a final feed
119 * after all the music data, or else this is a block. Either
120 * way, there is no need to process this chunk.
123 for (end_p = mainll_p->next; end_p != 0 &&
124 end_p->str != S_FEED; end_p = end_p->next) {
125 if (end_p->str == S_BAR)
130 break; /* end of MLL, get out */
132 /* update SSVs to beginning of next score */
133 for (m2_p = mainll_p->next; m2_p != end_p;
135 if (m2_p->str == S_SSV)
136 asgnssv(m2_p->u.ssv_p);
139 mainll_p = end_p; /* block, skip by it */
143 for (s = 1; s <= Score.staffs; s++) {
144 if (svpath(s, VISIBLE)->visible == YES)
145 procstaff(mainll_p, s);
148 /* update SSVs to beginning of next score */
149 for (m2_p = mainll_p->next; m2_p != end_p; m2_p = m2_p->next) {
150 if (m2_p->str == S_SSV)
151 asgnssv(m2_p->u.ssv_p);
165 * Abstract: Set all relative vertical coords for a staff in one score.
169 * Description: This function sets all remaining relative vertical coords
170 * for a given staff of a given score.
174 procstaff(start_p, s)
176 struct MAINLL *start_p; /* FEED at the start of this score */
177 int s; /* the staff we are to work on */
180 struct MAINLL *mainll_p;/* point along main linked list */
181 char *order; /* point at a subarray in markorder */
182 int stk; /* stacking order number */
183 int mk; /* mark type */
184 unsigned long do_which; /* bit map of which mark types to do */
185 float north, south; /* relative coords of staff */
186 float hb; /* height of "between" objects */
187 int k; /* loop variable */
190 debug(32, "procstaff file=%s line=%d s=%d", start_p->inputfile,
191 start_p->inputlineno, s);
193 /* set globals like Staffscale for use by the rest of the file */
197 * Each structure in rectab[] represents something to be drawn that
198 * is associated with this staff, beginning with the staff itself.
199 * The coordinates define the rectangle that surrounds the object.
200 * The rectangles' edges are horizontal and vertical. So if an object
201 * (like a slanted beam) doesn't fit well in such a recangle, multiple
202 * rectangles are used to enclose pieces of it, as in integration in
205 * The first part of this function does this for things that are above
206 * the staff. The second part does it for things that are below it.
207 * The third part does it for items that are to be centered (if
208 * possible) between two staffs. In the first two parts, rectangles
209 * are added to the table one at a time, working outwards from the
210 * staff. In the third part, they are piled on an imaginary baseline.
212 * Some objects (like note groups) already have an assigned position.
213 * and their rectangles are simply added to the table, regardless of
214 * whether they overlap preexisting rectangles.
216 * Some objects (like phrase marks) get their positions figured out
217 * now, by some unique algorithm that doesn't make use of the table of
218 * rectangles, and then their rectangles are added to the table, again
219 * not worrying about overlap with preexisting rectangles.
221 * Some objects (like "stuff" to be printed) make use of the table to
222 * figure out where their rectangles should be placed. They are placed
223 * as close to the staff (or baseline, for "between") as is possible
224 * without overlapping preexisting rectangles (or, in the case of
225 * chords, getting closer to the staff than allowed by "chorddist"; or
226 * in the case of rom, ital, bold, boldital, or rehearsal marks, closer
227 * than "dist"; or in the case of dynamics, closer than "dyndist").
228 * (And some things have their own "dist" to override these parameters,
229 * and the optional ability to force a distance regardless of overlap.)
230 * To see if the rectangle being added overlaps, first its east and
231 * west are tested. All previous rectangles that are "out of its way"
232 * horizontally are marked not "relevant"; the others are marked
233 * "relevant". As positions are tried, working outwards, positions
234 * that fail to avoid overlap are marked "tried". (For chords, and
235 * rom/ital/bold/boldital, previous rectangles that are closer to the
236 * staff than the stuff is allowed to come anyhow are pre-marked as if
241 * Fill rectab for the objects above this staff.
243 reclim = 0; /* rectab is initially empty */
245 dostaff(s, PL_ABOVE);
246 dogroups(start_p, s, PL_ABOVE);
247 dobeamalt(start_p, s, PL_ABOVE);
248 docurve(start_p, s, PL_ABOVE, DO_OTHERS);
249 dotuplet(start_p, s, PL_ABOVE);
250 docurve(start_p, s, PL_ABOVE, DO_PHRASE);
252 /* get stacking order of the user-controllable mark types */
253 order = svpath(s, ABOVEORDER)->markorder[PL_ABOVE];
255 /* loop on each possible stacking order number */
256 for (stk = 1; stk <= NUM_MARK; stk++) {
258 /* set bit map for each mark type that has this order number */
260 for (mk = 0; mk < NUM_MARK; mk++) {
261 if (order[mk] == stk) {
262 do_which |= (1L << mk);
265 /* if no marks, we're done; stacking orders are contiguous */
270 * Some mark types must have a unique order number, not shared
271 * with any others. For each of them, do a case statement to
272 * call their subroutine. The other ones all share the same
273 * subroutine, so call it in the default to do the mark types
274 * listed in the bit map.
277 case 1L << MK_LYRICS:
278 dolyrics(start_p, s, PL_ABOVE);
280 case 1L << MK_ENDING:
281 doendings(start_p, s);
283 case 1L << MK_REHEARSAL:
284 dorehears(start_p, s);
287 break; /* ignore for above */
289 domiscstuff(start_p, s, PL_ABOVE, do_which);
295 * Find the northernmost rectangle, for setting the staff's north.
296 * But don't let north be so close that things sticking out might
297 * almost touch another staff. Staffs smaller than a regular 5 line
298 * staff will still be given as much space. In any case, we want at
299 * least 3 stepsizes of white space.
301 north = staffvertspace(s) / 2.0 + 3.0 * Stepsize;
302 for (k = 0; k < reclim; k++) {
303 if (rectab[k].n > north)
308 * Fill rectab for the objects below this staff.
310 reclim = 0; /* rectab is initially empty */
312 dostaff(s, PL_BELOW);
313 dogroups(start_p, s, PL_BELOW);
314 dobeamalt(start_p, s, PL_BELOW);
315 docurve(start_p, s, PL_BELOW, DO_OTHERS);
316 dotuplet(start_p, s, PL_BELOW);
317 docurve(start_p, s, PL_BELOW, DO_PHRASE);
319 /* get stacking order of the user-controllable mark types */
320 order = svpath(s, BELOWORDER)->markorder[PL_BELOW];
322 /* loop on each possible stacking order number */
323 for (stk = 1; stk <= NUM_MARK; stk++) {
325 /* set bit map for each mark type that has this order number */
327 for (mk = 0; mk < NUM_MARK; mk++) {
328 if (order[mk] == stk) {
329 do_which |= (1L << mk);
332 /* if no marks, we're done; stacking orders are contiguous */
337 * Some mark types must have a unique order number, not shared
338 * with any others. For each of them, do a case statement to
339 * call their subroutine. The other ones all share the same
340 * subroutine, so call it in the default to do the mark types
341 * listed in the bit map.
344 case 1L << MK_LYRICS:
345 dolyrics(start_p, s, PL_BELOW);
347 case 1L << MK_ENDING:
348 case 1L << MK_REHEARSAL:
349 break; /* ignore for below */
354 domiscstuff(start_p, s, PL_BELOW, do_which);
360 * Find the southernmost rectangle, for setting the staff's south.
361 * But don't let south be so close that things sticking out might
362 * almost touch another staff. Staffs smaller than a regular 5 line
363 * staff will still be given as much space. In any case, we want at
364 * least 3 stepsizes of white space.
366 south = -(staffvertspace(s) / 2.0 + 3.0 * Stepsize);
367 for (k = 0; k < reclim; k++) {
368 if (rectab[k].s < south)
373 * Fill rectab for the objects between this staff and the one below.
375 reclim = 0; /* rectab is initially empty */
377 /* set up baseline, a rectangle of height 0 spanning the page */
378 rectab[reclim].w = 0;
379 rectab[reclim].e = PGWIDTH;
380 rectab[reclim].n = 0;
381 rectab[reclim].s = 0;
385 /* get stacking order of the user-controllable mark types */
386 order = svpath(s, BETWEENORDER)->markorder[PL_BETWEEN];
388 /* loop on each possible stacking order number */
389 for (stk = 1; stk <= NUM_MARK; stk++) {
391 /* set bit map for each mark type that has this order number */
393 for (mk = 0; mk < NUM_MARK; mk++) {
394 if (order[mk] == stk) {
395 do_which |= (1L << mk);
398 /* if no marks, we're done; stacking orders are contiguous */
403 * Some mark types must have a unique order number, not shared
404 * with any others. For each of them, do a case statement to
405 * call their subroutine. The other ones all share the same
406 * subroutine, so call it in the default to do the mark types
407 * listed in the bit map.
410 case 1L << MK_LYRICS:
411 dolyrics(start_p, s, PL_BETWEEN);
413 case 1L << MK_ENDING:
414 case 1L << MK_REHEARSAL:
416 break; /* ignore for between */
418 domiscstuff(start_p, s, PL_BETWEEN, do_which);
424 * Find the northernmost rectangle, for finding the height of these
428 for (k = 0; k < reclim; k++) {
429 if (rectab[k].n > hb)
434 * Set the relative north and south of every STAFF structure for this
435 * staff number on this score. (There's one per measure.) While
436 * we're at it, set RX to 0, in case anyone cares. Set the height of
437 * "between" objects in each STAFF, too.
439 for (mainll_p = start_p->next; mainll_p != 0 &&
440 mainll_p->str != S_FEED; mainll_p = mainll_p->next) {
442 if (mainll_p->str == S_STAFF &&
443 mainll_p->u.staff_p->staffno == s) {
445 mainll_p->u.staff_p->c[RN] = north;
446 mainll_p->u.staff_p->c[RX] = 0;
447 mainll_p->u.staff_p->c[RS] = south;
448 mainll_p->u.staff_p->heightbetween = hb;
456 * Abstract: Set up the rectangle for the staff itself.
460 * Description: This function puts into rectab the rectangle for the staff
461 * itself. The staff's relative vertical coords are not set now,
462 * though, because they must later be set to include all the
463 * objects associated with the staff.
469 int s; /* staff number */
470 int place; /* above or below? */
473 debug(32, "dostaff s=%d place=%d", s, place);
475 * Use the full page width, even though the staff will not actually
476 * reach the edges, due to margins, etc. This way nothing will ever
477 * fall beyond this base rectangle. Put a STDPAD of padding around
480 rectab[reclim].w = 0;
481 rectab[reclim].e = PGWIDTH;
483 if (place == PL_ABOVE) {
484 rectab[reclim].n = halfstaffhi(s) + Stdpad;
485 rectab[reclim].s = 0;
486 } else { /* PL_BELOW */
487 rectab[reclim].n = 0;
488 rectab[reclim].s = -(halfstaffhi(s) + Stdpad);
497 * Abstract: Set up rectangles & relative vert coords for staff's groups.
501 * Description: This function puts into rectab the rectangles for each group on
502 * this staff. The groups' relative vertical coords were already
503 * set in proclist() in beamstem.c.
507 dogroups(start_p, s, place)
509 struct MAINLL *start_p; /* FEED at the start of this score */
510 int s; /* staff number */
511 int place; /* above or below? */
514 struct MAINLL *mainll_p; /* point along main linked list */
515 int v; /* voice number */
518 debug(32, "dogroups file=%s line=%d s=%d place=%d", start_p->inputfile,
519 start_p->inputlineno, s, place);
521 * Loop through this score's part of the MLL.
523 for (mainll_p = start_p->next; mainll_p != 0 &&
524 mainll_p->str != S_FEED; mainll_p = mainll_p->next) {
526 * Whenever we find a structure for this staff (another
527 * measure of this staff), call llgrps() for each voice.
528 * If some voice doesn't exist, llgrps() will get a
529 * null pointer and just return.
531 if (mainll_p->str == S_STAFF &&
532 mainll_p->u.staff_p->staffno == s) {
534 for (v = 0; v < MAXVOICES; v++)
535 llgrps(mainll_p->u.staff_p,
536 mainll_p->u.staff_p->groups_p[v], place);
544 * Abstract: Set up rectangles for note and rest groups.
548 * Description: This function puts rectangles into rectab for all groups in
549 * this measure of this voice, for groups consisting of notes or
554 llgrps(staff_p, first_p, place)
556 struct STAFF *staff_p; /* point to the staff */
557 struct GRPSYL *first_p; /* point to first group */
558 int place; /* above or below? */
561 struct GRPSYL *gs_p; /* point at a group */
562 struct NOTE *note_p; /* point at a note */
563 double mx, my_offset, mheight, mwidth; /* multirest number coords */
564 int n; /* loop through notelist */
565 float asc, des, wid; /* ascent, descent, and width of acc */
569 * For each group that is notes or a rest, put a rectangle into rectab.
570 * However, on tablature staffs, don't do this for rests, since they
571 * aren't printed there.
573 for (gs_p = first_p; gs_p != 0; gs_p = gs_p->next) {
574 if (gs_p->grpcont == GC_SPACE)
577 if (gs_p->grpcont == GC_REST && is_tab_staff(gs_p->staffno))
580 if (place == PL_ABOVE && (
581 gs_p->basictime < -1 && svpath(staff_p->staffno,
582 PRINTMULTNUM)->printmultnum == YES ||
583 is_mrpt(gs_p) && svpath(staff_p->staffno,
584 NUMBERMRPT)->numbermrpt == YES
587 * Special case for multirests and measure repeats.
588 * The rest or mrpt symbol itself is inside the staff,
589 * so we don't have to worry about it. But we need to
590 * make a rectangle for the number, if the number is
593 (void)mrnum(staff_p, &mx, &my_offset, &mheight,
595 rectab[reclim].w = mx;
596 rectab[reclim].e = mx + mwidth;
597 rectab[reclim].n = my_offset + mheight;
598 rectab[reclim].s = 0;
604 /* for "below", no rectangles are needed for multirests */
605 if (gs_p->basictime < -1)
609 * We have a normal note or rest group. Make a rectangle for
610 * it, making sure it reaches the center staff line.
612 rectab[reclim].w = gs_p->c[AW];
613 rectab[reclim].e = gs_p->c[AE];
615 if (place == PL_ABOVE) {
616 rectab[reclim].n = MAX(gs_p->c[RN], 0);
617 rectab[reclim].s = 0;
618 } else { /* PL_BELOW */
619 rectab[reclim].n = 0;
620 rectab[reclim].s = MIN(gs_p->c[RS], 0);
625 /* if a clef precedes this group, make a rectangle for it */
626 if (gs_p->clef != NOCLEF) {
627 float north, south; /* clef coords */
629 rectab[reclim].e = gs_p->c[AW] - Staffscale * CLEFPAD;
630 rectab[reclim].w = rectab[reclim].e - Staffscale *
631 clefwidth(gs_p->clef, YES);
632 (void)clefvert(gs_p->clef, YES, &north, &south);
633 rectab[reclim].n = north * Staffscale;
634 rectab[reclim].s = south * Staffscale;
640 * An additional rectangle is needed for each note that has an
641 * accidental. This is because although the east/west group
642 * boundaries include any accidentals, the north/south
643 * boundaries ingore them. It needs to be this way because,
644 * for other reasons, like ties, we want the north/south group
645 * boundaries to consider only the note heads. But for general
646 * stuff, the accidentals should also be considered. The
647 * rectangles added below take care of this.
648 * Similarly, if the top or bottom note is on a line and has a
649 * dot in the space away from the group, it needs a rectangle.
651 if (gs_p->grpcont == GC_NOTES &&
652 ! is_tab_staff(gs_p->staffno)) {
653 for (n = 0; n < gs_p->nnotes; n++) {
654 note_p = &gs_p->notelist[n];
656 if (gs_p->dots != 0 &&
657 note_p->stepsup % 2 == 0 &&
658 (n == 0 && note_p->ydotr > 0.0 ||
659 n == gs_p->nnotes - 1 && note_p->ydotr < 0.0)){
660 float radius; /* of a dot, + pad */
661 radius = Stdpad + Staffscale *
662 ascent(FONT_MUSIC, (note_p->
663 notesize == GS_NORMAL ?
664 DFLT_SIZE : SMALLSIZE), C_DOT);
665 rectab[reclim].n = gs_p->c[RY] +
666 note_p->ydotr + radius;
667 rectab[reclim].s = gs_p->c[RY] +
668 note_p->ydotr - radius;
669 rectab[reclim].w = gs_p->c[AX] +
670 gs_p->xdotr - radius;
671 rectab[reclim].e = gs_p->c[AX] +
672 gs_p->xdotr + radius +
673 (gs_p->dots - 1) * 2.0 *
678 if (note_p->accidental == '\0')
681 /* this note has an acc; create a rectangle */
682 accdimen(note_p, &asc, &des, &wid);
687 rectab[reclim].w = gs_p->c[AX] + note_p->waccr;
688 rectab[reclim].e = rectab[reclim].w + wid;
689 rectab[reclim].n = note_p->c[RY] + asc;
690 rectab[reclim].s = note_p->c[RY] - des;
701 * Abstract: Set up rectangles for beams and alternation bars.
705 * Description: This function puts into rectab rectangles for each beam or
706 * alternation bar on this staff in this score, where the thing
707 * is on the "place" side of the notes.
711 dobeamalt(start_p, s, place)
713 struct MAINLL *start_p; /* FEED at the start of this score */
714 int s; /* staff number */
715 int place; /* above or below? */
718 struct MAINLL *mainll_p; /* point along main linked list */
719 struct GRPSYL *gs_p; /* point along a GRPSYL linked list */
720 int v; /* voice number */
723 debug(32, "dobeamalt file=%s line=%d s=%d place=%d", start_p->inputfile,
724 start_p->inputlineno, s, place);
726 * Loop through this score's part of the MLL.
728 for (mainll_p = start_p->next; mainll_p != 0 &&
729 mainll_p->str != S_FEED; mainll_p = mainll_p->next) {
731 * Whenever we find a structure for this staff (another
732 * measure of this staff), loop through its voices.
734 if (mainll_p->str == S_STAFF &&
735 mainll_p->u.staff_p->staffno == s) {
737 for (v = 0; v < MAXVOICES; v++) {
738 for (gs_p = mainll_p->u.staff_p->groups_p[v];
739 gs_p != 0; gs_p = gs_p->next) {
741 * Whenever we find the first group of
742 * a nongrace beamed or alted set with
743 * the stem direction on the side we
744 * are dealing with, call onebeamalt()
745 * to put rectangle(s) in rectab.
746 * But not for cross staff beams.
747 * Grace groups are included in the
748 * following nongrace group's rectangle
751 if (gs_p->grpcont == GC_NOTES &&
752 gs_p->grpvalue == GV_NORMAL &&
753 gs_p->beamloc == STARTITEM &&
754 gs_p->beamto == CS_SAME) {
756 if (place == PL_ABOVE &&
757 gs_p->stemdir == UP ||
759 gs_p->stemdir == DOWN)
772 * Abstract: Set up rectangle(s) for one beam or alternation bar.
776 * Description: This function puts zero or more rectangles in rectab for the
777 * beam or alternation that starts at the given group. The longer
778 * and more slanted the beam/alternation is, the more rectangles
779 * will be necessary to enclose it without wasting a lot of space.
780 * If the beam/alt lies within the staff, there's no need to make
781 * any rectangles. All rectangles' inner edges are the center
788 struct GRPSYL *gs_p; /* initially points to first group */
791 float stemshift; /* how far a stem is from its group's X */
792 float x1, y1; /* coords of left end of beam/alt */
793 float x2, y2; /* coords of right end of beam/alt */
797 * Set coords of the ends of the beam/alt. We are given the first
798 * group, but must search forward to the end to find the last group,
799 * being careful to ignore embedded grace groups. We adjust the X
800 * coords (for groups that can have stems) because stems are offset
801 * from their group's X. The Y coords can't always be based on the
802 * group boundaries, because there might be "with" lists on the
803 * abnormal (beam) side, and they don't affect the position of the beam.
806 y1 = getstemendvert(gs_p);
808 while (gs_p != 0 && (gs_p->grpvalue == GV_ZERO ||
809 gs_p->beamloc != ENDITEM))
812 pfatal("beam or alt group has no ENDITEM");
815 y2 = getstemendvert(gs_p);
817 stemshift = getstemshift(gs_p);
819 if (gs_p->basictime >= 2) {
820 /* the groups have stems (if first one does, others must too)*/
821 if (gs_p->stemdir == UP) {
830 /* make zero or more rectangles for this beam/alt */
831 linerects(x1, y1, x2, y2, gs_p->stemdir, halfstaffhi(gs_p->staffno));
835 * Name: getstemendvert()
837 * Abstract: Find the vertical coord of the end of a stem.
841 * Description: This function is given a GRPSYL of a group that has either a
842 * real, visible stem, or an invisible one (alt). If finds
843 * the relative vertical coordinate of the end of the stems
844 * farthest from the note head(s).
850 struct GRPSYL *gs_p; /* the group in question */
853 double y; /* the answer */
856 if (gs_p->nwith == 0 || gs_p->normwith == YES) {
858 * Either there is no "with" list, or it's on the notes' end
859 * of the stem. So we can use the group boundary.
861 y = gs_p->stemdir == UP ? gs_p->c[RN] : gs_p->c[RS];
864 * There is a "with" list at this end of the stem. Find where
865 * the end of the stem is by applying the stem's length to the
866 * farthest note on the opposite side.
868 if (gs_p->stemdir == UP)
869 y = gs_p->notelist[ gs_p->nnotes - 1 ].c[RY] +
872 y = gs_p->notelist[ 0 ].c[RY] - gs_p->stemlen;
875 /* counteract the stem shortening that was done in finalstemadjust() */
876 if (gs_p->beamloc != NOITEM) {
877 if (gs_p->stemdir == UP) {
878 y += (W_WIDE * Stdpad / 2.0);
880 y -= (W_WIDE * Stdpad / 2.0);
890 * Abstract: Set up rectangle(s) to contain a (possibly) slanted line.
894 * Description: This function puts zero or more rectangles in rectab to contain
895 * a (possibly) slanted line. The longer and more slanted the
896 * line is, the more rectangles will be necessary to enclose it
897 * without wasting a lot of space. If the line lies within the
898 * staff, there's no need to make any rectangles. All rectangles'
899 * inner edges are the center staff line.
903 linerects(x1, y1, x2, y2, side, halfstaff)
905 double x1, y1; /* coords of left end of line */
906 double x2, y2; /* coords of right end of line */
907 int side; /* side to favor, UP or DOWN */
908 double halfstaff; /* half the staff height */
911 float slope, yintercept;/* of a line a STDPAD beyond beam/alt */
912 float deltax; /* width of one rectangle */
913 float leftx, rightx; /* X coord of sides of a rectangle */
916 /* if line is within staff, no need for any rectangles */
917 if (fabs(y1) < halfstaff && fabs(y2) < halfstaff)
921 * If this beam/alt is level, make one big rectangle, and get out.
924 rectab[reclim].w = x1;
925 rectab[reclim].e = x2;
927 rectab[reclim].n = y1;
928 rectab[reclim].s = 0;
930 rectab[reclim].n = 0;
931 rectab[reclim].s = y1;
938 * We may need multiple rectangles. Make them narrow enough so that
939 * the change in Y across the width of one is one STEPSIZE. The
940 * rightmost one will probably be narrower, using whatever room
941 * remains. The equation of our line is y = slope * x + yintercept.
943 slope = (y1 - y2) / (x1 - x2);
944 yintercept = y1 - slope * x1;
945 deltax = Stepsize / fabs(slope);
947 for (leftx = x1; leftx < x2; leftx += deltax) {
948 rightx = MIN(x2, leftx + deltax);
949 rectab[reclim].w = leftx;
950 rectab[reclim].e = rightx;
952 rectab[reclim].n = slope * (slope > 0 ? rightx : leftx)
954 rectab[reclim].s = 0;
956 rectab[reclim].n = 0;
957 rectab[reclim].s = slope * (slope > 0 ? leftx : rightx)
967 * Abstract: Get point list and set up rectangles for tie/slur/bend/phrase.
971 * Description: This function goes through all ties, slurs, bends, phrases for
972 * staff. The first time it is called for a staff (which is for
973 * place "above") it calls a function to set up the curve list.
974 * Whichever time it is called, it calls a function to put
975 * rectangles in rectab.
979 docurve(start_p, s, place, do_which)
981 struct MAINLL *start_p; /* FEED at the start of this score */
982 int s; /* staff number */
983 int place; /* above or below? */
984 int do_which; /* which stuff types are to be handled */
987 struct MAINLL *mainll_p; /* loop through main linked list */
988 struct STUFF *stuff_p; /* point along a STUFF list */
989 float halfstaff; /* half the staff height */
992 debug(32, "docurve file=%s line=%d s=%d place=%d do_which=%d",
993 start_p->inputfile, start_p->inputlineno, s, place, do_which);
994 halfstaff = halfstaffhi(s);
997 * Loop through this score's part of the MLL, looking for matching
1000 for (mainll_p = start_p->next; mainll_p != 0 &&
1001 mainll_p->str != S_FEED; mainll_p = mainll_p->next) {
1003 if (mainll_p->str != S_STAFF ||
1004 mainll_p->u.staff_p->staffno != s)
1007 /* loop through each stuff of the indicated type */
1008 for (stuff_p = mainll_p->u.staff_p->stuff_p;
1009 stuff_p != 0; stuff_p = stuff_p->next){
1011 switch (stuff_p->stuff_type) {
1016 break; /* docurve works on these */
1018 continue; /* for some other function */
1022 * If we are to do phrases and this is not a phrase, or
1023 * vice versa, skip this.
1025 if ((do_which == DO_PHRASE) !=
1026 (stuff_p->stuff_type == ST_PHRASE))
1030 * When we're in here the first time (for PL_ABOVE),
1031 * call a function to set up the curve list. For
1032 * everything but ST_PHRASE it also sets "place".
1034 if (place == PL_ABOVE) {
1035 switch (stuff_p->stuff_type) {
1037 /* don't call tieslur_points now if the
1038 * positions of the tie/slur's endpoints
1039 * would change later due to CSS */
1040 if (css_affects_tieslurbend(stuff_p,
1044 tieslur_points(mainll_p, stuff_p);
1047 tabslur_points(mainll_p, stuff_p);
1050 /* don't call bend_points now if the
1051 * positions of the bend's endpoints
1052 * would change later due to CSS */
1053 if (css_affects_tieslurbend(stuff_p,
1057 bend_points(mainll_p, stuff_p);
1060 /* don't call phrase_points now if the
1061 * positions of the phrase's endpoints
1062 * would change later due to CSS */
1063 if (css_affects_phrase(stuff_p,
1067 phrase_points(mainll_p, stuff_p);
1073 * Make rectangles no matter what side of the staff the
1074 * curve is supposed to be on, because, depending on
1075 * how high or low the notes are, rectangles may be
1076 * needed even on the opposite side you'd expect.
1078 if (stuff_p->crvlist_p != 0) {
1079 curverect(s, stuff_p, halfstaff);
1088 * Abstract: Put rectangles in rectab for a tie, slur, bend, or phrase.
1092 * Description: This function puts rectangles in rectab for a tie, slur, bend,
1093 * or phrase. Each segment of the curve gets one or more
1094 * rectangles, depending on how long and how slanted it is. To do
1095 * this, we call curvepiecerect().
1099 curverect(s, stuff_p, halfstaff)
1101 int s; /* staff number */
1102 struct STUFF *stuff_p; /* the curve's STUFF */
1103 double halfstaff; /* half the staff height */
1106 struct CRVLIST *point_p; /* point at a phrase point */
1107 float x1, y1; /* coords of left end of a segment */
1108 float x2, y2; /* coords of right end of a segment */
1109 float midx, midy; /* middle of one segment of a curve */
1113 * Loop through the curve list. For each pair of neighboring points,
1114 * there is a segment of the curve. For items that are actually
1115 * straight line segments, call curvepiecerect() once. But for actual
1116 * curves, find the midpoint, and call curvepiecerect() for each half.
1117 * This way we more closely approximate the real curve.
1119 for (point_p = stuff_p->crvlist_p; point_p->next != 0;
1120 point_p = point_p->next) {
1124 x2 = point_p->next->x;
1125 y2 = point_p->next->y;
1127 if (stuff_p->stuff_type == ST_BEND ||
1128 stuff_p->stuff_type == ST_TABSLUR) {
1129 /* bend, or slur on tab or tabnote */
1130 curvepiecerect(x1, y1, x2, y2, halfstaff);
1133 midx = (x1 + x2) / 2.0;
1134 midy = curve_y_at_x(stuff_p->crvlist_p, midx);
1135 curvepiecerect(x1, y1, midx, midy, halfstaff);
1136 curvepiecerect(midx, midy, x2, y2, halfstaff);
1142 * Name: curvepiecerect()
1144 * Abstract: Put rects in rectab for a piece of a tie, slur, bend, or phrase.
1148 * Description: This function puts rectangles in rectab for one piece of a
1149 * curve. The piece gets one or more rectangles, depending on how
1150 * long and how slanted it is.
1154 curvepiecerect(x1, y1, x2, y2, halfstaff)
1156 double x1, y1; /* coords of left end of the piece */
1157 double x2, y2; /* coords of right end of the piece */
1158 double halfstaff; /* half the staff height */
1161 float slope, yintercept;/* of a line a segment */
1162 float deltax; /* width of one rectangle */
1163 float leftx, rightx; /* X coord of sides of a rectangle */
1166 /* if whole piece is within the staff, no rectangles are needed */
1167 if (fabs(y1) < halfstaff && fabs(y2) < halfstaff)
1171 * If this piece is level, make 1 big rectangle, and continue.
1174 rectab[reclim].w = x1;
1175 rectab[reclim].e = x2;
1176 rectab[reclim].n = MAX(y1 + 2 * Stdpad, 0.0);
1177 rectab[reclim].s = MIN(y1 - 2 * Stdpad, 0.0);
1183 * We may need multiple rectangles. Make them narrow enough so that
1184 * the change in Y across the width of one is one Stepsize. The
1185 * rightmost one will probably be narrower, using whatever room
1186 * remains. The equation of our line is
1187 * y = slope * x + yintercept
1188 * Initially each rectangle only includes its segment (plus padding),
1189 * but then we extend it to reach the center line of the staff.
1191 slope = (y1 - y2) / (x1 - x2);
1192 yintercept = y1 - slope * x1;
1193 deltax = Stepsize / fabs(slope);
1195 for (leftx = x1; leftx < x2; leftx += deltax) {
1196 rightx = MIN(x2, leftx + deltax);
1198 rectab[reclim].w = leftx;
1199 rectab[reclim].e = rightx;
1202 * For north and south boundaries, use the side of the rect
1203 * that sticks out more, to err on the side of making the rect
1204 * big enough. Also add in padding, to 1) allow for the fact
1205 * that the real curve probably bulges out beyond our segment
1206 * approximation, and 2) because we don't want anything
1207 * actually touching the curve.
1209 rectab[reclim].n = slope * (slope > 0.0 ? rightx : leftx) +
1210 yintercept + 2.0 * Stdpad;
1211 rectab[reclim].s = slope * (slope < 0.0 ? rightx : leftx) +
1212 yintercept - 2.0 * Stdpad;
1214 /* rectangle must reach the center line of the staff */
1215 if (rectab[reclim].n < 0.0)
1216 rectab[reclim].n = 0.0;
1217 if (rectab[reclim].s > 0.0)
1218 rectab[reclim].s = 0.0;
1227 * Abstract: Set up rectangles for tuplet brackets.
1231 * Description: This function puts into rectab rectangles for each tuplet
1232 * bracket on this staff in this score, where the thing is on
1233 * the "place" side of the notes.
1238 dotuplet(start_p, s, place)
1240 struct MAINLL *start_p; /* FEED at the start of this score */
1241 int s; /* staff number */
1242 int place; /* above or below? */
1245 struct MAINLL *mainll_p; /* point along main linked list */
1246 struct GRPSYL *gs_p; /* point along a GRPSYL linked list */
1247 int v; /* voice number */
1250 debug(32, "dotuplet file=%s line=%d s=%d place=%d", start_p->inputfile,
1251 start_p->inputlineno, s, place);
1253 /* tuplet brackets are never printed on tablature staffs */
1254 if (is_tab_staff(s))
1258 * Loop through this score's part of the MLL.
1260 for (mainll_p = start_p->next; mainll_p != 0 &&
1261 mainll_p->str != S_FEED; mainll_p = mainll_p->next) {
1263 * Whenever we find a structure for this staff (another
1264 * measure of this staff), loop through its voices.
1266 if (mainll_p->str == S_STAFF &&
1267 mainll_p->u.staff_p->staffno == s) {
1269 for (v = 0; v < MAXVOICES; v++) {
1270 for (gs_p = mainll_p->u.staff_p->groups_p[v];
1271 gs_p != 0; gs_p = gs_p->next) {
1273 * Whenever we find the first group of
1274 * a tuplet with a bracket on the
1275 * "place" side of the group, call
1276 * onetuplet() to put rectangle(s) in
1279 if ((gs_p->tuploc == STARTITEM ||
1280 gs_p->tuploc == LONEITEM) &&
1281 gs_p->printtup != PT_NEITHER) {
1283 if (tupdir(gs_p, mainll_p->u.
1286 onetuplet(mainll_p->u.
1287 staff_p, gs_p, place);
1298 * Abstract: Set up rectangle(s) for one tuplet bracket or number.
1302 * Description: If this tuplet is not going to be given a bracket (like because
1303 * its notes are already beamed), this function just makes one
1304 * rectangle, for the number. Otherwise, this function puts zero
1305 * or more rectangles in rectab for the tuplet that starts at the
1306 * given group. The longer and more slanted the tuplet bracket
1307 * is, the more rectangles will be necessary to enclose it without
1308 * wasting a lot of space. All rectangles' inner edges are the
1309 * center staff line.
1313 onetuplet(staff_p, start_p, place)
1315 struct STAFF *staff_p; /* point to the staff we're on */
1316 struct GRPSYL *start_p; /* points to first group in tuplet */
1317 int place; /* above or below? */
1320 struct GRPSYL *gs_p; /* point to a group in tuplet */
1321 float stemshift; /* how far a stem is from its group's X */
1322 float x1, y1; /* coords of left end of beam/alt */
1323 float x2, y2; /* coords of right end of beam/alt */
1324 float numeast, numwest; /* horizontal coords of the tuplet number */
1325 float height; /* height of the tuplet number */
1329 * Set coords of the ends of the tuplet. We are given the first
1330 * group, but must search forward to the end to find the last group,
1331 * being careful to ignore embedded grace groups. We adjust the X
1332 * coords because brackets reach beyond their group's X.
1334 x1 = start_p->c[AX];
1335 y1 = (place == PL_ABOVE ? start_p->c[RN] : start_p->c[RS])
1336 + start_p->tupextend;
1338 for (gs_p = start_p; gs_p != 0 && (gs_p->grpvalue == GV_ZERO ||
1339 gs_p->tuploc != ENDITEM && gs_p->tuploc != LONEITEM);
1343 pfatal("tuplet has no ENDITEM");
1346 y2 = (place == PL_ABOVE ? gs_p->c[RN] : gs_p->c[RS]) + gs_p->tupextend;
1349 * If there is not going to be a bracket, create one rectangle for the
1350 * tuplet number, and return.
1352 if (tupgetsbrack(start_p) == NO) {
1353 (void)tupnumsize(start_p, &numwest, &numeast, &height, staff_p);
1354 rectab[reclim].n = (y1 + y2) / 2 + height / 2;
1355 rectab[reclim].s = (y1 + y2) / 2 - height / 2;
1356 rectab[reclim].w = numwest;
1357 rectab[reclim].e = numeast;
1363 /* there is going to be a bracket; extend x coords to reach to end */
1364 stemshift = getstemshift(gs_p);
1369 /* make zero or more rectangles for this bracket */
1370 linerects(x1, y1, x2, y2, place == PL_ABOVE ? UP : DOWN,
1371 halfstaffhi(gs_p->staffno));
1375 * Name: domiscstuff()
1377 * Abstract: Set up rectangles and vert coords for miscellaneous STUFF.
1381 * Description: This function puts into rectab a rectangle for each STUFF
1382 * structure in the "place" relationship to the given staff on
1383 * this score, except for stuff types that have special,
1384 * dedicated functions for their type. It also sets their
1385 * relative vertical coordinates.
1389 domiscstuff(start_p, s, place, do_which)
1391 struct MAINLL *start_p; /* FEED at the start of this score */
1392 int s; /* staff number */
1393 int place; /* above, below, or between? */
1394 unsigned long do_which; /* which stuff types are to be handled */
1397 struct MAINLL *mainll_p; /* loop through main linked list */
1398 struct STUFF *stuff_p; /* point along a STUFF list */
1399 float high; /* height of a rectangle */
1400 float len; /* length of a cresc/descresc */
1401 float lowpart; /* dist between stuff's Y and S */
1402 float dist; /* how close chord can get to staff */
1403 int stype; /* stuff type */
1406 debug(32, "domiscstuff file=%s line=%d s=%d place=%d do_which=%ld",
1407 start_p->inputfile, start_p->inputlineno, s, place, do_which);
1409 * Loop through this score's part of the MLL. Whenever we find a
1410 * structure for this staff (another measure), loop through its
1411 * STUFF list, dealing with each STUFF that is above, below, or
1412 * between, as specified by "place".
1414 for (mainll_p = start_p->next; mainll_p != 0 &&
1415 mainll_p->str != S_FEED; mainll_p = mainll_p->next) {
1417 if (mainll_p->str != S_STAFF ||
1418 mainll_p->u.staff_p->staffno != s) {
1422 for (stuff_p = mainll_p->u.staff_p->stuff_p;
1423 stuff_p != 0; stuff_p = stuff_p->next) {
1425 if (stuff_p->place != place) {
1429 stype = stuff_p->stuff_type;
1431 /* if wrong type for this pass, exit */
1432 if (stype == ST_MUSSYM) {
1433 if ((do_which & (1L << MK_MUSSYM)) == 0)
1435 } else if (stype == ST_OCTAVE) {
1436 if ((do_which & (1L << MK_OCTAVE)) == 0)
1438 } else if (stype != ST_PHRASE &&
1439 stuff_p->modifier == TM_DYN) {
1440 if ((do_which & (1L << MK_DYN)) == 0)
1442 } else if (stype != ST_PHRASE &&
1443 IS_CHORDLIKE(stuff_p->modifier)) {
1444 if ((do_which & (1L << MK_CHORD)) == 0)
1446 } else if (IS_TEXT(stype)) {
1447 if ((do_which & (1L << MK_OTHERTEXT)) == 0)
1452 * We found a "stuff" that needs to be positioned.
1453 * First find its total height, and the height of the
1454 * part of it below its Y coord.
1456 /* avoid 'used before set' warning */
1457 high = lowpart = 0.0;
1459 /* handle various types differently */
1467 /* don't handle these types here; */
1468 /* they have their own subroutines */
1477 /* high is string's height */
1478 high = strheight( stuff_p->string);
1479 lowpart = strdescent( stuff_p->string);
1482 * If a chord grid is to be printed under the
1483 * string, the Y and N of the stuff remain
1484 * unchanged, but its S is lowered by the total
1485 * height of the grid. So add its height to
1486 * both "high" and "lowpart".
1488 if (stuff_p->modifier == TM_CHORD && svpath(s,
1489 GRIDSWHEREUSED)->gridswhereused == YES) {
1490 struct GRID *grid_p;
1491 float gnorth, gsouth;
1493 grid_p = findgrid(stuff_p->string);
1494 /* if none, skip this; stuff.c warned*/
1498 gridsize(grid_p, stuff_p->all ? 0 :
1499 mainll_p->u.staff_p->staffno,
1501 (float *)0, (float *)0);
1503 high += gnorth - gsouth;
1504 lowpart += gnorth - gsouth;
1510 /* height depends on length */
1511 len = stuff_p->c[AE] - stuff_p->c[AW];
1514 high = 2.00 * STEPSIZE + 2 * STDPAD;
1516 high = 2.67 * STEPSIZE + 2 * STDPAD;
1518 high = 3.33 * STEPSIZE + 2 * STDPAD;
1521 high *= Score.staffscale;
1530 pfatal("unknown stuff type (%d)", stype);
1534 * Now find "dist", the minimum distance it should be
1535 * put from the staff.
1537 if (stuff_p->dist_usage == SD_NONE) {
1539 * The user didn't specify the dist, so we get
1540 * it from the appropriate parameter or hard-
1541 * coded value, as the case may be. For
1542 * parameters, if the stuff belongs to the
1543 * score as a whole ("all"), use the Score
1544 * value instead of svpath.
1546 /* if "dyn", fake to use same logic as cresc */
1547 if (stuff_p->modifier == TM_DYN)
1556 stuff_p->modifier)) {
1571 stuff_p->modifier)) {
1575 svpath(s, CHORDDIST)->
1581 svpath(s, DIST)->dist;
1588 dist = halfstaffhi(s) +
1589 STEPSIZE * Score.staffscale *
1592 dist = halfstaffhi(s) +
1593 Stepsize * svpath(s,
1602 /* the user specified the dist, so use that */
1604 dist = halfstaffhi(s) +
1605 STEPSIZE * stuff_p->dist;
1607 dist = halfstaffhi(s) +
1608 Stepsize * stuff_p->dist;
1612 if (stuff_p->dist_usage == SD_FORCE) {
1614 * The user is forcing this dist, so don't
1615 * stack; just put it there. Note: the user
1616 * cannot specify "dist" for "between" items.
1618 if (stuff_p->place == PL_ABOVE) {
1619 rectab[reclim].n = dist + high;
1620 rectab[reclim].s = dist;
1621 stuff_p->c[RS] = dist;
1622 } else { /* PL_BELOW */
1623 rectab[reclim].n = -dist;
1624 rectab[reclim].s = -dist - high;
1625 stuff_p->c[RS] = -dist - high;
1627 rectab[reclim].e = stuff_p->c[AE];
1628 rectab[reclim].w = stuff_p->c[AW];
1632 * Stack the usual way. For the case of
1633 * "between", stackit() will ignore "dist".
1635 stuff_p->c[RS] = stackit(stuff_p->c[AW],
1636 stuff_p->c[AE], high, dist, place);
1639 stuff_p->c[RN] = stuff_p->c[RS] + high;
1640 stuff_p->c[RY] = stuff_p->c[RS] + lowpart;
1648 * Abstract: Set up rectangles and vert coords for lyrics.
1652 * Description: This function puts into rectab a rectangle for each verse in
1653 * the "place" relationship to the given staff on this score.
1657 dolyrics(start_p, s, place)
1659 struct MAINLL *start_p; /* FEED at the start of this score */
1660 int s; /* staff number */
1661 int place; /* above, below, or between? */
1664 int *versenums; /* malloc'ed array of verse numbers in score */
1665 struct MAINLL *mainll_p;/* point along main linked list */
1666 struct STAFF *staff_p; /* point at a staff structure */
1667 struct GRPSYL *gs_p; /* point at a syllable */
1668 float protrude; /* farthest protrusion of rectangle */
1669 int vfound; /* number of verse numbers found in score */
1670 int v; /* verse number */
1671 int begin, end, delta; /* for looping over verses in proper order */
1672 float dist; /* how close lyrics can get to staff */
1673 float farwest, fareast; /* farthest east and west of any syllable */
1674 float baseline; /* baseline of a verse of syllables */
1675 float maxasc, maxdes; /* max ascent & descent of syllables */
1676 int gotverse0; /* is there a verse 0 (centered verse)? */
1677 int gototherverse; /* is there a normal verse (not 0)? */
1678 int n, k, j; /* loop variables */
1681 debug(32, "dolyrics file=%s line=%d s=%d place=%d", start_p->inputfile,
1682 start_p->inputlineno, s, place);
1683 /* if there are no lyrics in this song, get out now */
1688 * Allocate an array containing room for all the verse numbers used in
1689 * this score. Maxverses is the number of verse numbers used in the
1690 * whole user input, so this will certainly be enough.
1692 MALLOCA(int, versenums, Maxverses);
1695 * Loop through this score's part of the MLL, noting whether verse 0
1696 * (the centered verse) and/or other verses exist on the "place" side
1697 * of the staff. We have to find this out before actually processing
1698 * the verses, because verse 0 is to be treated as a normal verse if
1699 * and only if there are no other verses.
1703 for (mainll_p = start_p->next; mainll_p != 0 &&
1704 mainll_p->str != S_FEED; mainll_p = mainll_p->next) {
1706 * Whenever we find a structure for this staff (another
1707 * measure of this staff), loop through its verse headcells.
1709 if (mainll_p->str == S_STAFF &&
1710 mainll_p->u.staff_p->staffno == s) {
1711 staff_p = mainll_p->u.staff_p;
1712 for (n = 0; n < staff_p->nsyllists; n++) {
1713 if (staff_p->sylplace[n] == place) {
1714 if (staff_p->syls_p[n]->vno == 0)
1717 gototherverse = YES;
1723 /* if no verses, get out now */
1724 if (gotverse0 == NO && gototherverse == 0) {
1730 * Loop through this score's part of the MLL, recording all the verse
1731 * numbers that occur on the "place" side of the staff in versenums[].
1732 * Verse 0 may or may not be included, depending on the above results.
1733 * Also set farwest and fareast.
1735 vfound = 0; /* no verses have been found yet */
1736 farwest = PGWIDTH; /* init it all the way east */
1737 fareast = 0; /* init it all the way west */
1738 for (mainll_p = start_p->next; mainll_p != 0 &&
1739 mainll_p->str != S_FEED; mainll_p = mainll_p->next) {
1741 * Whenever we find a structure for this staff (another
1742 * measure of this staff), loop through its verse headcells.
1744 if (mainll_p->str == S_STAFF &&
1745 mainll_p->u.staff_p->staffno == s) {
1747 staff_p = mainll_p->u.staff_p;
1749 for (n = 0; n < staff_p->nsyllists; n++) {
1751 if (staff_p->sylplace[n] == place) {
1753 * We found a verse number. Search the
1754 * the array to see if it's already
1755 * been found. If not, insert it into
1756 * versenums[] in the right place, so
1757 * that they'll end up being in order
1758 * (actually, reverse order).
1760 v = staff_p->syls_p[n]->vno;
1761 /* ignore verse 0 if others exist */
1762 if (v == 0 && gototherverse == YES)
1764 for (k = 0; k < vfound &&
1765 v < versenums[k]; k++) {
1768 if (k == vfound || v > versenums[k]) {
1769 for (j = vfound; j > k; j--) {
1774 vfound++; /* found one more */
1778 * If any syl sticks out farther than
1779 * any previous one, extend farwest or
1782 for (gs_p = staff_p->syls_p[n];
1783 gs_p != 0; gs_p = gs_p->next) {
1785 if (gs_p->c[AW] < farwest)
1786 farwest = gs_p->c[AW];
1787 if (gs_p->c[AE] > fareast)
1788 fareast = gs_p->c[AE];
1796 * Enclose all the syllables of all the verses (of this place) in one
1797 * big rectangle. Pad on west and east by 8 step sizes. Pretend the
1798 * rectangle is PGHEIGHT high. We don't actually know yet how high
1799 * it is, and this will prevent it from getting between the staff and
1800 * anything else. Later in this function we will correct the entry
1801 * that stackit put in rectab, to reflect the true height. For above
1802 * and below cases, don't let it get any closer than 2 step sizes to
1803 * the staff. The half-height of a one-line staff is regarded as 1
1804 * instead of the true 0, to give a little breathing room.
1806 if (place == PL_BETWEEN)
1809 dist = halfstaffhi(s) + 2.0 * Stepsize;
1811 (void)stackit(farwest - 8 * STEPSIZE, fareast + 8 * STEPSIZE, PGHEIGHT,
1815 * Find the greatest protrusion of any currently existing rectangle
1816 * that horizontally is within the span of our new rectangle. That's
1817 * the same as the top or bottom of the new rectangle.
1819 if (place == PL_BELOW)
1820 protrude = rectab[reclim - 1].n;
1822 protrude = rectab[reclim - 1].s;
1825 * Loop through the verses, from the inside out. setting the relative
1826 * vertical coords of their syllables. When necessary, we also insert
1827 * new syllables on the next score for continuing underscores.
1829 if (place == PL_BELOW) { /* work downward from staff */
1830 begin = vfound - 1; /* first verse number */
1831 end = -1; /* beyond last verse number */
1833 } else { /* above and between both work upwards from bottom */
1834 begin = 0; /* last verse number */
1835 end = vfound; /* before first verse number */
1838 for (n = begin; n != end; n += delta) {
1840 * Find the farthest any syllable ascends and descends from the
1841 * baseline of the verse.
1843 getvsize(start_p, s, place, versenums[n], &maxasc, &maxdes);
1846 * Set the baseline for this verse, based on where we're
1847 * pushing up against (the last verse we did, or earlier
1848 * things), and how far this verse sticks out.
1850 if (place == PL_BELOW)
1851 baseline = protrude - maxasc;
1852 else /* above or between */
1853 baseline = protrude + maxdes;
1855 /* set syllables' vertical coords; continue underscores */
1856 setsylvert(start_p, s, place, versenums[n], baseline);
1858 /* set new lower bound, for next time through loop */
1859 if (place == PL_BELOW)
1860 protrude = baseline - maxdes;
1861 else /* above or between */
1862 protrude = baseline + maxasc;
1864 } /* for every verse */
1867 * If there was a verse 0 (centered verse) and also normal verses, then
1868 * in the above code we have handled only the normal verses, and we now
1869 * need to handle verse 0.
1871 if (gotverse0 == YES && gototherverse == YES) {
1872 float mid; /* RY of the middle of the normal verses */
1873 struct RECTAB rec; /* one rectangle */
1875 /* get ascent and descent of verse 0 */
1876 getvsize(start_p, s, place, 0, &maxasc, &maxdes);
1879 * We will use stackit's "dist" mechanism to try to get verse 0
1880 * to line up with the center of the other verses. The last
1881 * rectangle in rectab is currently the normal verses', but the
1882 * one coord isn't really set right yet. Fortunately, the
1883 * "protrude" variable is what we need for that coord.
1885 if (place == PL_BELOW) {
1886 mid = (rectab[reclim - 1].n + protrude) / 2.0;
1887 dist = -mid - (maxasc + maxdes) / 2.0;
1889 mid = (protrude + rectab[reclim - 1].s) / 2.0;
1890 dist = mid - (maxasc + maxdes) / 2.0;
1894 * Find the easternmost and westernmost points of verse 0.
1895 * It's easier to loop through all the syllables than to try to
1896 * find the first and last syllables on the line.
1898 farwest = PGWIDTH; /* init it all the way east */
1899 fareast = 0; /* init it all the way west */
1900 for (mainll_p = start_p->next;
1901 mainll_p != 0 && mainll_p->str != S_FEED;
1902 mainll_p = mainll_p->next) {
1904 if (mainll_p->str != S_STAFF ||
1905 mainll_p->u.staff_p->staffno != s)
1908 staff_p = mainll_p->u.staff_p;
1909 for (n = 0; n < staff_p->nsyllists; n++) {
1910 if (staff_p->sylplace[n] == place &&
1911 staff_p->syls_p[n]->vno == 0) {
1912 for (gs_p = staff_p->syls_p[n];
1913 gs_p != 0; gs_p = gs_p->next) {
1915 if (gs_p->c[AW] < farwest)
1916 farwest = gs_p->c[AW];
1917 if (gs_p->c[AE] > fareast)
1918 fareast = gs_p->c[AE];
1925 * Squeeze the regular verses' rectangle to zero so that it
1926 * won't affect verse 0's. We hope they wouldn't interfere
1927 * anyway, but the +8 and -8 might make them. The regular
1928 * verses' rectangle will be corrected later anyway.
1930 rectab[reclim - 1].n = rectab[reclim - 1].s = 0;
1933 * Stack verse 0's rectangle and set its baseline. We have to
1934 * play games with "place", because for "between" stackit
1935 * ignores "dist", but we need it to use "dist".
1937 baseline = stackit(farwest - 8 * STEPSIZE,
1938 fareast + 8 * STEPSIZE, maxasc + maxdes, dist,
1939 place == PL_BETWEEN ? PL_ABOVE : place) + maxdes;
1942 * Switch verse 0's rectangle and the normal verses' so that
1943 * the later code can always use reclim-1 for the normal.
1945 rec = rectab[reclim - 2];
1946 rectab[reclim - 2] = rectab[reclim - 1];
1947 rectab[reclim - 1] = rec;
1949 setsylvert(start_p, s, place, 0, baseline);
1953 * Now that we know how high this rectangle really is, correct it in
1954 * rectab. Make it reach the center of the staff/baseline, to prevent
1955 * anything later from getting in between there.
1957 if (place == PL_BELOW) {
1958 rectab[reclim - 1].n = 0;
1959 rectab[reclim - 1].s = protrude;
1960 } else { /* above or between */
1961 rectab[reclim - 1].n = protrude;
1962 rectab[reclim - 1].s = 0;
1971 * Abstract: Get the maximum ascent and descent for a verse on a score.
1975 * Description: This function returns (through pointers) the maximum ascent and
1976 * descent of a verse on this score. Usually this is the standard
1977 * ascent and descent of the font, but it could be greater if
1978 * there are font or size changes inside some syllable.
1982 getvsize(start_p, s, place, v, maxasc_p, maxdes_p)
1984 struct MAINLL *start_p; /* FEED at the start of this score */
1985 int s; /* staff number */
1986 int place; /* above, below, or between? */
1987 int v; /* verse number */
1988 float *maxasc_p, *maxdes_p; /* ascent and descent to be returned */
1991 int lyricsfont; /* that is set for this staff */
1992 int lyricssize; /* that is set for this staff */
1993 float asc, des; /* max ascent & descent of syllables */
1994 struct MAINLL *mainll_p;/* point along main linked list */
1995 struct STAFF *staff_p; /* point at a staff structure */
1996 struct GRPSYL *gs_p; /* point at a syllable */
1997 int k; /* loop variable */
2001 * Get the standard max ascent and descent for any syllable.
2003 lyricsfont = svpath(s, LYRICSFONT)->lyricsfont;
2004 lyricssize = svpath(s, LYRICSSIZE)->lyricssize;
2005 *maxasc_p = fontascent(lyricsfont, lyricssize) * Staffscale;
2006 *maxdes_p = fontdescent(lyricsfont, lyricssize) * Staffscale;
2009 * Find the farthest any syllable ascends and descends from the
2010 * baseline of the verse. Start with the standard amount for this font
2011 * size. If the loop finds any weird syllable with bigger characters
2012 * embedded, they will be increased.
2014 for (mainll_p = start_p->next; mainll_p != 0 && mainll_p->str
2015 != S_FEED; mainll_p = mainll_p->next) {
2017 if (mainll_p->str != S_STAFF ||
2018 mainll_p->u.staff_p->staffno != s)
2021 /* found a STAFF of the number we're dealing with */
2022 staff_p = mainll_p->u.staff_p;
2025 * See if this verse is present in this staff,
2026 * and if so, loop through it.
2028 for (k = 0; k < staff_p->nsyllists; k++) {
2030 if (staff_p->sylplace[k] == place &&
2031 staff_p->syls_p[k]->vno == v) {
2033 for (gs_p = staff_p->syls_p[k]; gs_p != 0;
2034 gs_p = gs_p->next) {
2036 * If asc or des is greater
2037 * for this syl, save it.
2039 asc = strascent(gs_p->syl);
2041 des = strdescent(gs_p->syl);
2043 if (asc > *maxasc_p)
2045 if (des > *maxdes_p)
2049 /* no need to look any more */
2053 } /* for every MLL stucture in score */
2057 * Name: setsylvert()
2059 * Abstract: Set the maximum ascent and descent for a verse on a score.
2063 * Description: This function, using the given baseline, sets the relative
2064 * vertical coords of each syllable in the verse on this score.
2065 * If there are any nonnull syllables, it calls a function to
2066 * continue underscores if need be.
2070 setsylvert(start_p, s, place, v, baseline)
2072 struct MAINLL *start_p; /* FEED at the start of this score */
2073 int s; /* staff number */
2074 int place; /* above, below, or between? */
2075 int v; /* verse number */
2076 double baseline; /* baseline of a verse of syllables */
2079 struct MAINLL *mainll_p;/* point along main linked list */
2080 struct STAFF *staff_p; /* point at a staff structure */
2081 struct GRPSYL *gs_p; /* point at a syllable */
2082 struct MAINLL *laststaff_p; /* point last staff that has a syllable */
2083 struct GRPSYL *lastgs_p;/* point at last nonnull syllable in a verse */
2084 int k; /* loop variable */
2088 * Loop through all these syllables as before, setting their relative
2091 lastgs_p = 0; /* set later to last nonnull syl, if exists */
2092 laststaff_p = 0; /* set later to staff containing lastgs_p */
2094 for (mainll_p = start_p->next; mainll_p != 0 && mainll_p->str
2095 != S_FEED; mainll_p = mainll_p->next) {
2097 if (mainll_p->str != S_STAFF ||
2098 mainll_p->u.staff_p->staffno != s)
2101 /* found a STAFF of the number we're dealing with */
2102 staff_p = mainll_p->u.staff_p;
2105 * See if this verse is present in this staff,
2106 * and if so, loop through it.
2108 for (k = 0; k < staff_p->nsyllists; k++) {
2110 if (staff_p->sylplace[k] == place &&
2111 staff_p->syls_p[k]->vno == v) {
2113 for (gs_p = staff_p->syls_p[k]; gs_p != 0;
2114 gs_p = gs_p->next) {
2116 if (gs_p->syl == 0) {
2120 gs_p->c[RY] = baseline;
2122 gs_p->c[RN] = baseline
2123 + strascent(gs_p->syl);
2125 gs_p->c[RS] = baseline
2126 - strdescent(gs_p->syl);
2128 /* remember last nonnull syl */
2129 if (gs_p->syl[0] != '\0') {
2131 laststaff_p = mainll_p;
2136 } /* for every MLL stucture in score */
2139 * At this point, if this score has any nonnull syllables for
2140 * this verse, lastgs_p points at the last one and laststaff_p
2141 * points at its STAFF. If that last syllable ends in '_' or
2142 * '-', we may need to continue this character onto the next
2143 * score, so call a function to do that.
2145 if (lastgs_p != 0 && has_extender(lastgs_p->syl))
2146 cont_extender(laststaff_p, place, v);
2152 * Abstract: Set a rectangle for pedal marks, if there are any.
2156 * Description: This function puts a rectangle into rectab for pedal marks, if
2157 * there are any on this score. It also sets their relative
2158 * vertical coordinates.
2164 struct MAINLL *start_p; /* FEED at the start of this score */
2165 int s; /* staff number */
2168 struct MAINLL *mainll_p; /* loop through main linked list */
2169 struct STUFF *stuff_p; /* point along a STUFF list */
2170 float protrude; /* farthest protrusion of rectangle */
2171 float lowpoint; /* the lowest any mark goes */
2172 float asc; /* ascent of a pedal mark */
2173 float hi; /* height of a pedal mark */
2174 int k; /* loop variable */
2177 debug(32, "dopedal file=%s line=%d s=%d", start_p->inputfile,
2178 start_p->inputlineno, s);
2180 * Find the greatest protrusion of any currently existing rectangle.
2183 for (k = 0; k < reclim; k++) {
2184 if (rectab[k].s < protrude)
2185 protrude = rectab[k].s;
2191 * Loop through this score's part of the MLL. Whenever we find a
2192 * structure for this staff (another measure), loop through its
2193 * STUFF list, setting coords for each pedal mark.
2195 for (mainll_p = start_p->next; mainll_p != 0 &&
2196 mainll_p->str != S_FEED; mainll_p = mainll_p->next) {
2198 if (mainll_p->str != S_STAFF ||
2199 mainll_p->u.staff_p->staffno != s)
2202 for (stuff_p = mainll_p->u.staff_p->stuff_p;
2203 stuff_p != 0; stuff_p = stuff_p->next) {
2205 if (stuff_p->stuff_type != ST_PEDAL)
2209 * Whichever pedal character this is, always use
2210 * C_BEGPED if pedstyle is P_LINE and the "Ped." string
2211 * for the other cases. For the former, all three
2212 * characters are the same height; and for the latter,
2213 * this string is taller than the "*". This also
2214 * handles the pedal continuation situation.
2216 stuff_p->c[RN] = protrude;
2217 if (svpath(s, PEDSTYLE)->pedstyle == P_LINE) {
2218 asc = ascent(FONT_MUSIC, DFLT_SIZE, C_BEGPED);
2219 hi = height(FONT_MUSIC, DFLT_SIZE, C_BEGPED);
2220 } else { /* P_PEDSTAR or P_ALTPEDSTAR */
2221 asc = strascent(Ped_start);
2222 hi = strheight(Ped_start);
2225 asc *= Score.staffscale;
2226 hi *= Score.staffscale;
2231 stuff_p->c[RY] = protrude - asc;
2232 stuff_p->c[RS] = protrude - hi;
2234 if (stuff_p->c[RS] < lowpoint)
2235 lowpoint = stuff_p->c[RS];
2240 * If we found pedal mark(s), put one big rectangle in rectab, spanning
2241 * the width of the page.
2244 rectab[reclim].n = protrude;
2245 rectab[reclim].s = lowpoint;
2246 rectab[reclim].w = 0;
2247 rectab[reclim].e = PGWIDTH;
2256 * Abstract: Set up rectangles and vert coords for ending marks.
2260 * Description: This function puts into rectab rectangles for ending marks.
2261 * Also, MARKCOORD structures get linked to BARs for them.
2265 doendings(start_p, s)
2267 struct MAINLL *start_p; /* FEED at the start of this score */
2268 int s; /* staff number */
2271 struct MAINLL *mainll_p;/* point along main linked list */
2272 struct BAR *bar_p; /* point at a bar or pseudobar on this score */
2275 debug(32, "doendings file=%s line=%d s=%d", start_p->inputfile,
2276 start_p->inputlineno, s);
2277 /* if endings are not to be drawn over this staff, get out */
2278 if (has_ending(s) == NO)
2281 /* point at pseudobar in clefsig that immediately follows this feed */
2282 mainll_p = start_p->next;
2283 bar_p = mainll_p->u.clefsig_p->bar_p;
2286 * If an ending starts at the pseudobar, or is continuing on from the
2287 * previous score, handle it, along with any following continguous ones.
2289 if (bar_p->endingloc != NOITEM) {
2291 * Search forward for the end of this ending (or following
2292 * contiguous ones), or the end of the score, whichever comes
2295 while ( ! (mainll_p->str == S_BAR &&
2296 mainll_p->u.bar_p->endingloc == ENDITEM)
2297 && mainll_p->str != S_FEED) {
2299 mainll_p = mainll_p->next;
2302 /* handle ending(s) from start to this bar or feed */
2303 storeend(start_p, mainll_p, s);
2305 /* if feed, there's nothing more to look for */
2306 if (mainll_p->str == S_FEED)
2309 /* point after this bar at end of this ending(s) */
2310 mainll_p = mainll_p->next;
2314 * Search the rest of the score for contiguous groups of endings.
2316 while (mainll_p != 0 && mainll_p->str != S_FEED) {
2318 /* find another bar; return if there aren't any more */
2319 while (mainll_p != 0 && mainll_p->str != S_BAR &&
2320 mainll_p->str != S_FEED)
2321 mainll_p = mainll_p->next;
2322 if (mainll_p == 0 || mainll_p->str == S_FEED)
2326 * We found another bar. If it isn't associated with an
2327 * ending, point beyond it and continue to go look for the
2330 if (mainll_p->u.bar_p->endingloc == NOITEM) {
2331 mainll_p = mainll_p->next;
2336 * This bar is the start of an ending. Search forward for the
2337 * end of this ending (or following contiguous ones), or the
2338 * end of the score, whichever comes first.
2341 while ( ! (mainll_p->str == S_BAR &&
2342 mainll_p->u.bar_p->endingloc == ENDITEM)
2343 && mainll_p->str != S_FEED) {
2345 mainll_p = mainll_p->next;
2348 /* handle ending(s) from start to this bar or feed */
2349 storeend(start_p, mainll_p, s);
2351 /* if feed, there's nothing more to look for */
2352 if (mainll_p->str == S_FEED)
2355 /* point after this bar at end of this ending */
2356 mainll_p = mainll_p->next;
2363 * Abstract: Set up rectangles and vert coords for contiguous endings.
2367 * Description: This function is given the starting and ending bars of a group
2368 * of continguous ending marks on a staff. The starting "bar"
2369 * may be the pseudobar at the start of the score; and the ending
2370 * bar may be the end of the score. This function applies stackit
2371 * to them as a unit. It adds another rectangle to rectab to
2372 * prevent anything later from getting in between the ending(s)
2373 * and the staff. Then, for the starting bar of each ending in
2374 * the group, it allocates a MARKCOORD structure.
2378 storeend(start_p, end_p, s)
2380 struct MAINLL *start_p; /* the start of these ending(s) */
2381 struct MAINLL *end_p; /* the end of these ending(s) */
2382 int s; /* staff number */
2385 struct MAINLL *mainll_p;/* point along main linked list */
2386 struct BAR *bar_p; /* point at a bar or pseudobar on this score */
2387 struct MARKCOORD *mark_p; /* we allocate these for bars to point at */
2388 float west, east; /* extremities of group of ending(s) */
2389 float south; /* their bottom boundary */
2393 * Find the west and east boundaries of the ending(s).
2395 if (start_p->str == S_FEED)
2396 west = start_p->next->u.clefsig_p->bar_p->c[AX]; /* pseudobar */
2398 west = start_p->u.bar_p->c[AX]; /* normal bar */
2400 if (end_p->str == S_FEED)
2401 east = PGWIDTH - eff_rightmargin(end_p); /* end of score */
2403 east = end_p->u.bar_p->c[AX]; /* normal bar */
2405 /* make a rectangle out of the ending(s) and find where they go */
2406 south = stackit(west, east, ENDINGHEIGHT, (double)0.0, PL_ABOVE);
2409 * Superimpose another rectangle on top of the one stackit put there;
2410 * one that reaches down to the staff. This ensures that nothing later
2411 * will get between the ending(s) and the staff.
2413 rectab[reclim].n = south + ENDINGHEIGHT;
2414 rectab[reclim].s = 0;
2415 rectab[reclim].e = east;
2416 rectab[reclim].w = west;
2420 * If the pseudobar has an ending, calloc a markcoord structure and put
2421 * it in the pseudobar's linked list of them.
2423 if (start_p->str == S_FEED) {
2424 bar_p = start_p->next->u.clefsig_p->bar_p;
2425 CALLOC(MARKCOORD, mark_p, 1);
2426 mark_p->next = bar_p->ending_p;
2427 bar_p->ending_p = mark_p;
2428 mark_p->staffno = (short)s;
2433 * Loop through this part of the score. Wherever there is a bar that
2434 * is the start of an ending, calloc a markcoord structure and put it
2435 * in the bar's linked list of them.
2437 for (mainll_p = start_p; mainll_p != end_p; mainll_p = mainll_p->next) {
2438 if (mainll_p->str != S_BAR)
2440 bar_p = mainll_p->u.bar_p;
2441 if (bar_p->endingloc != STARTITEM)
2443 CALLOC(MARKCOORD, mark_p, 1);
2444 mark_p->next = bar_p->ending_p;
2445 bar_p->ending_p = mark_p;
2446 mark_p->staffno = (short)s;
2454 * Abstract: Set up rectangles and vert coords for rehearsal marks.
2458 * Description: This function puts into rectab rectangles for rehearsal marks.
2459 * Also, MARKCOORD structures get linked to BARs for them.
2463 dorehears(start_p, s)
2465 struct MAINLL *start_p; /* FEED at the start of this score */
2466 int s; /* staff number */
2469 struct MAINLL *mainll_p;/* point along main linked list */
2470 struct BAR *bar_p; /* point at a bar or pseudobar on this score */
2471 struct MARKCOORD *mark_p; /* we allocate these for bars to point at */
2472 float west, east; /* of a rehearsal mark */
2473 float south; /* of a rehearsal mark */
2474 float height; /* of a rehearsal mark */
2475 float dist; /* distance from center of staff */
2476 int dopseudo; /* do the pseudobar's rehearsal mark? */
2477 char *reh_string; /* string for the reh mark */
2480 debug(32, "dorehears file=%s line=%d s=%d", start_p->inputfile,
2481 start_p->inputlineno, s);
2482 /* if rehearsal marks are not to be drawn over this staff, get out */
2483 if (has_ending(s) == NO)
2486 /* point at pseudobar in clefsig that immediately follows this feed */
2487 mainll_p = start_p->next;
2488 bar_p = mainll_p->u.clefsig_p->bar_p;
2490 /* if there's a rehearsal mark at the pseudobar, note that fact */
2491 if (bar_p->reh_type != REH_NONE)
2497 * Loop through the score, dealing with the pseudobar (if it has a
2498 * rehearsal mark), and all real bars that have a rehearsal mark.
2500 for ( ; mainll_p != 0 && mainll_p->str != S_FEED;
2501 mainll_p = mainll_p->next) {
2503 if (dopseudo == YES || mainll_p->str == S_BAR &&
2504 mainll_p->u.bar_p->reh_type != REH_NONE){
2505 if (dopseudo == YES)
2508 bar_p = mainll_p->u.bar_p;
2511 * Find the size of the rehearsal label, including 6
2512 * more points to allow for the box around it. Make
2513 * its first character be centered over the bar line.
2514 * Place it by using stackit.
2516 reh_string = get_reh_string(bar_p->reh_string, s);
2517 height = strheight(reh_string);
2518 west = bar_p->c[AX] - left_width(reh_string);
2519 east = west + strwidth(reh_string);
2521 if (bar_p->dist_usage == SD_NONE) {
2522 /* get the usual dist */
2523 dist = svpath(s, DIST)->dist;
2525 /* override with this bar's dist */
2528 /* convert to inches from center of staff */
2529 dist = halfstaffhi(s) + STEPSIZE * dist;
2531 if (bar_p->dist_usage == SD_FORCE) {
2533 * The user is forcing this dist, so don't
2534 * stack; just put it there.
2537 rectab[reclim].n = south + height;
2538 rectab[reclim].s = south;
2539 rectab[reclim].e = east;
2540 rectab[reclim].w = west;
2543 /* stack the usual way */
2544 south = stackit(west, east, height, dist,
2549 * Allocate and link a MARKCOORD, and put the necessary
2552 CALLOC(MARKCOORD, mark_p, 1);
2553 mark_p->next = bar_p->reh_p;
2554 bar_p->reh_p = mark_p;
2555 mark_p->staffno = (short)s;
2556 mark_p->ry = south + strdescent(reh_string);
2564 * Abstract: Place a rectangle and add it to rectab.
2566 * Returns: south boundary of the new rectangle
2568 * Description: This function puts the given rectangle into rectab. It is put
2569 * as close to the staff or baseline as is possible without
2570 * overlapping rectangles already in rectab, and without letting
2571 * it get any closer to the staff/baseline than "dist" STEPSIZE.
2575 stackit(west, east, height, dist, place)
2577 double west; /* west edge of the new rectangle */
2578 double east; /* east edge of the new rectangle */
2579 double height; /* height of the new rectangle */
2580 double dist; /* min dist from item to center line of staff*/
2581 int place; /* above, below, or between? */
2584 float north, south; /* trial boundaries for new rectangle */
2585 int try; /* which element of rectab to try */
2586 int overlap; /* does our rectangle overlap existing ones? */
2587 int j; /* loop variable */
2591 * For each rectangle in rectab, decide whether (based on
2592 * its horizontal coords) it could possibly overlap with our
2593 * new rectangle. If it's totally left or right of ours, it
2594 * can't. We allow a slight overlap (FUDGE) so that round
2595 * off errors don't stop us from packing things as tightly
2598 for (j = 0; j < reclim; j++) {
2599 if (rectab[j].w + FUDGE > east ||
2600 rectab[j].e < west + FUDGE)
2601 rectab[j].relevant = NO;
2603 rectab[j].relevant = YES;
2607 * Set up first trial position for this rectangle: "dist" inches
2608 * away from the center line of the staff. For "between", it always
2609 * starts at the baseline.
2611 north = south = 0.0; /* prevent useless 'used before set' warning */
2614 /* work downward from staff, allowing "dist" distance */
2616 south = north - height;
2619 /* work upward from staff, allowing "dist" distance */
2621 north = south + height;
2624 /* work upward from baseline */
2631 * Mark the "tried" field for all relevant rectangles. This says
2632 * whether we have already tried using their boundaries for positioning
2633 * our rectangle. Any rectangle that is closer to the staff/baseline
2634 * than we want to allow, we mark as if we have tried it already.
2636 for (j = 0; j < reclim; j++) {
2637 if (rectab[j].relevant == YES) {
2638 if (place == PL_BELOW && rectab[j].s > north ||
2639 place != PL_BELOW && rectab[j].n < south)
2640 rectab[j].tried = YES;
2642 rectab[j].tried = NO;
2647 * Keep trying positions for this rectangle, working outwards from the
2648 * first trial position. When we find one that doesn't overlap an
2649 * existing rectangle, break. This has to succeed at some point, at
2650 * at the outermost rectangle position if not earlier.
2654 for (j = 0; j < reclim; j++) {
2655 /* ignore ones too far east or west */
2656 if (rectab[j].relevant == NO)
2659 /* if all south or north, okay; else overlap */
2660 if (rectab[j].s + FUDGE <= north &&
2661 rectab[j].n >= south + FUDGE) {
2667 /* if no rectangle overlapped, we found a valid place */
2672 * Something overlapped, so we have to try again. Find the
2673 * innermost relevant outer rectangle boundary that hasn't been
2674 * tried already, to use as the next trial position for our
2675 * rectangle's inner boundary.
2678 for (j = 0; j < reclim; j++) {
2679 /* ignore ones too far east or west */
2680 if (rectab[j].relevant == NO || rectab[j].tried == YES)
2684 * If this is the first relevant one we haven't tried,
2685 * or if this is farther in than the innermost so far,
2686 * save it as being the new innermost so far.
2688 if (place == PL_BELOW) {
2689 if (try == -1 || rectab[j].s > rectab[try].s)
2692 if (try == -1 || rectab[j].n < rectab[try].n)
2698 pfatal("bug in stackit()");
2701 * Mark this one as having been tried (for next time around, if
2702 * necessary). Set new trial values for north and south of our
2705 rectab[try].tried = YES;
2706 if (place == PL_BELOW) {
2707 north = rectab[try].s;
2708 south = north - height;
2710 south = rectab[try].n;
2711 north = south + height;
2714 } /* end of while loop trying positions for this rectangle */
2717 * We found the correct position for the new rectangle. Enter it
2720 rectab[reclim].n = north;
2721 rectab[reclim].s = south;
2722 rectab[reclim].e = east;
2723 rectab[reclim].w = west;
2731 * Name: inc_reclim()
2733 * Abstract: Increment no. of rectangles, and realloc more if we run out.
2737 * Description: This function increments reclim, the index into rectab. If it
2738 * finds that rectab[reclim] is now beyond the end of the space
2739 * that's been allocated, it does a realloc to get more space.
2745 /* when first called, relvert will have allocated this many */
2746 static int rectabsize = RECTCHUNK;
2751 /* if rectab[reclim] is still valid, no need to allocate more */
2752 if (reclim < rectabsize)
2755 /* must allocate another chunk of rectangles */
2756 rectabsize += RECTCHUNK;
2757 REALLOC(RECTAB, rectab, rectabsize);