chiark / gitweb /
Merge branch 'arkkra' into shiny
[mup] / mup / mup / relvert.c
1 /* Copyright (c) 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005 by Arkkra Enterprises */
2 /* All rights reserved */
3 /*
4  * Name:        relvert.c
5  *
6  * Description: This file contains functions for setting all remaining
7  *              relative vertical coordinates.
8  */
9
10 #include <string.h>
11 #include "defines.h"
12 #include "structs.h"
13 #include "globals.h"
14
15 /* how many rectangles to malloc initially and at each realloc if needed */
16 #define RECTCHUNK       (100)
17
18 /* rectangle structure; see procscore() prologue for explanation of its use */
19 struct RECTAB {
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? */
26 };
27 static struct RECTAB *rectab;   /* ptr to malloc'ed and realloc'ed array */
28
29 /* this fudge factor prevents roundoff error from causing overlap */
30 #define FUDGE   (0.001)
31
32 /* these symbols tell certain subroutines which things to work on */
33 #define DO_OTHERS       0       /* default */
34 #define DO_PHRASE       1
35
36
37 static int reclim;              /* index after last rectangle in rectab */
38
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,
47                 double halfstaff));
48 static void docurve P((struct MAINLL *start_p, int s, int place,
49                 int do_which));
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,
52                 double halfstaff));
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,
55                 int place));
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,
62                 double baseline));
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,
68                 int place));
69 static void inc_reclim P((void));
70 \f
71 /*
72  * Name:        relvert()
73  *
74  * Abstract:    Set all relative vertical coords not already set.
75  *
76  * Returns:     void
77  *
78  * Description: This function sets all remaining relative vertical coords.
79  *              It calls procstaff() once for each staff in each score to
80  *              do this.
81  */
82
83 void
84 relvert()
85
86 {
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? */
92
93
94         debug(16, "relvert");
95         /*
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.
99          */
100         initstructs();                  /* clean out old SSV info */
101
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);
107         }
108
109         /*
110          * Initially allocate RECTCHUNK rectangles.  If we find we need more at
111          * some point, we'll realloc to get more.
112          */
113         MALLOC(RECTAB, rectab, RECTCHUNK);
114
115         for (;;) {
116                 /*
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.
121                  */
122                 gotbar = NO;
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)
126                                 gotbar = YES;
127                 }
128                 if (gotbar == NO) {
129                         if (end_p == 0)
130                                 break;          /* end of MLL, get out */
131
132                         /* update SSVs to beginning of next score */
133                         for (m2_p = mainll_p->next; m2_p != end_p;
134                                                 m2_p = m2_p->next) {
135                                 if (m2_p->str == S_SSV)
136                                         asgnssv(m2_p->u.ssv_p);
137                         }
138
139                         mainll_p = end_p;       /* block, skip by it */
140                         continue;
141                 }
142
143                 for (s = 1; s <= Score.staffs; s++) {
144                         if (svpath(s, VISIBLE)->visible == YES)
145                                 procstaff(mainll_p, s);
146                 }
147
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);
152                 }
153
154                 if (end_p == 0)
155                         break;
156                 mainll_p = end_p;
157         }
158
159         FREE(rectab);
160 }
161 \f
162 /*
163  * Name:        procstaff()
164  *
165  * Abstract:    Set all relative vertical coords for a staff in one score.
166  *
167  * Returns:     void
168  *
169  * Description: This function sets all remaining relative vertical coords
170  *              for a given staff of a given score.
171  */
172
173 static void
174 procstaff(start_p, s)
175
176 struct MAINLL *start_p;         /* FEED at the start of this score */
177 int s;                          /* the staff we are to work on */
178
179 {
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 */
188
189
190         debug(32, "procstaff file=%s line=%d s=%d", start_p->inputfile,
191                         start_p->inputlineno, s);
192
193         /* set globals like Staffscale for use by the rest of the file */
194         set_staffscale(s);
195
196         /*
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
203          * calculus.
204          *
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.
211          *
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.
215          *
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.
220          *
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
237          * "tried".)
238          */
239
240         /*
241          * Fill rectab for the objects above this staff.
242          */
243         reclim = 0;                     /* rectab is initially empty */
244
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);
251
252         /* get stacking order of the user-controllable mark types */
253         order = svpath(s, ABOVEORDER)->markorder[PL_ABOVE];
254
255         /* loop on each possible stacking order number */
256         for (stk = 1; stk <= NUM_MARK; stk++) {
257
258                 /* set bit map for each mark type that has this order number */
259                 do_which = 0;
260                 for (mk = 0; mk < NUM_MARK; mk++) {
261                         if (order[mk] == stk) {
262                                 do_which |= (1L << mk);
263                         }
264                 }
265                 /* if no marks, we're done; stacking orders are contiguous */
266                 if (do_which == 0)
267                         break;
268
269                 /*
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.
275                  */
276                 switch (do_which) {
277                 case 1L << MK_LYRICS:
278                         dolyrics(start_p, s, PL_ABOVE);
279                         break;
280                 case 1L << MK_ENDING:
281                         doendings(start_p, s);
282                         break;
283                 case 1L << MK_REHEARSAL:
284                         dorehears(start_p, s);
285                         break;
286                 case 1L << MK_PEDAL:
287                         break;  /* ignore for above */
288                 default:
289                         domiscstuff(start_p, s, PL_ABOVE, do_which);
290                         break;
291                 }
292         }
293
294         /*
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.
300          */
301         north = staffvertspace(s) / 2.0 + 3.0 * Stepsize;
302         for (k = 0; k < reclim; k++) {
303                 if (rectab[k].n > north)
304                         north = rectab[k].n;
305         }
306
307         /*
308          * Fill rectab for the objects below this staff.
309          */
310         reclim = 0;                     /* rectab is initially empty */
311
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);
318
319         /* get stacking order of the user-controllable mark types */
320         order = svpath(s, BELOWORDER)->markorder[PL_BELOW];
321
322         /* loop on each possible stacking order number */
323         for (stk = 1; stk <= NUM_MARK; stk++) {
324
325                 /* set bit map for each mark type that has this order number */
326                 do_which = 0;
327                 for (mk = 0; mk < NUM_MARK; mk++) {
328                         if (order[mk] == stk) {
329                                 do_which |= (1L << mk);
330                         }
331                 }
332                 /* if no marks, we're done; stacking orders are contiguous */
333                 if (do_which == 0)
334                         break;
335
336                 /*
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.
342                  */
343                 switch (do_which) {
344                 case 1L << MK_LYRICS:
345                         dolyrics(start_p, s, PL_BELOW);
346                         break;
347                 case 1L << MK_ENDING:
348                 case 1L << MK_REHEARSAL:
349                         break;  /* ignore for below */
350                 case 1L << MK_PEDAL:
351                         dopedal(start_p, s);
352                         break;
353                 default:
354                         domiscstuff(start_p, s, PL_BELOW, do_which);
355                         break;
356                 }
357         }
358
359         /*
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.
365          */
366         south = -(staffvertspace(s) / 2.0 + 3.0 * Stepsize);
367         for (k = 0; k < reclim; k++) {
368                 if (rectab[k].s < south)
369                         south = rectab[k].s;
370         }
371
372         /*
373          * Fill rectab for the objects between this staff and the one below.
374          */
375         reclim = 0;                     /* rectab is initially empty */
376
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;
382         inc_reclim();
383
384
385         /* get stacking order of the user-controllable mark types */
386         order = svpath(s, BETWEENORDER)->markorder[PL_BETWEEN];
387
388         /* loop on each possible stacking order number */
389         for (stk = 1; stk <= NUM_MARK; stk++) {
390
391                 /* set bit map for each mark type that has this order number */
392                 do_which = 0;
393                 for (mk = 0; mk < NUM_MARK; mk++) {
394                         if (order[mk] == stk) {
395                                 do_which |= (1L << mk);
396                         }
397                 }
398                 /* if no marks, we're done; stacking orders are contiguous */
399                 if (do_which == 0)
400                         break;
401
402                 /*
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.
408                  */
409                 switch (do_which) {
410                 case 1L << MK_LYRICS:
411                         dolyrics(start_p, s, PL_BETWEEN);
412                         break;
413                 case 1L << MK_ENDING:
414                 case 1L << MK_REHEARSAL:
415                 case 1L << MK_PEDAL:
416                         break;  /* ignore for between */
417                 default:
418                         domiscstuff(start_p, s, PL_BETWEEN, do_which);
419                         break;
420                 }
421         }
422
423         /*
424          * Find the northernmost rectangle, for finding the height of these
425          * objects between.
426          */
427         hb = 0;
428         for (k = 0; k < reclim; k++) {
429                 if (rectab[k].n > hb)
430                         hb = rectab[k].n;
431         }
432
433         /*
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.
438          */
439         for (mainll_p = start_p->next; mainll_p != 0 &&
440                         mainll_p->str != S_FEED; mainll_p = mainll_p->next) {
441
442                 if (mainll_p->str == S_STAFF &&
443                                 mainll_p->u.staff_p->staffno == s) {
444
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;
449                 }
450         }
451 }
452 \f
453 /*
454  * Name:        dostaff()
455  *
456  * Abstract:    Set up the rectangle for the staff itself.
457  *
458  * Returns:     void
459  *
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.
464  */
465
466 static void
467 dostaff(s, place)
468
469 int s;                          /* staff number */
470 int place;                      /* above or below? */
471
472 {
473         debug(32, "dostaff s=%d place=%d", s, place);
474         /*
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
478          * it vertically.
479          */
480         rectab[reclim].w = 0;
481         rectab[reclim].e = PGWIDTH;
482
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);
489         }
490
491         inc_reclim();
492 }
493 \f
494 /*
495  * Name:        dogroups()
496  *
497  * Abstract:    Set up rectangles & relative vert coords for staff's groups.
498  *
499  * Returns:     void
500  *
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.
504  */
505
506 static void
507 dogroups(start_p, s, place)
508
509 struct MAINLL *start_p;         /* FEED at the start of this score */
510 int s;                          /* staff number */
511 int place;                      /* above or below? */
512
513 {
514         struct MAINLL *mainll_p;        /* point along main linked list */
515         int v;                          /* voice number */
516
517
518         debug(32, "dogroups file=%s line=%d s=%d place=%d", start_p->inputfile,
519                         start_p->inputlineno, s, place);
520         /*
521          * Loop through this score's part of the MLL.
522          */
523         for (mainll_p = start_p->next; mainll_p != 0 &&
524                         mainll_p->str != S_FEED; mainll_p = mainll_p->next) {
525                 /*
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.
530                  */
531                 if (mainll_p->str == S_STAFF &&
532                                 mainll_p->u.staff_p->staffno == s) {
533
534                         for (v = 0; v < MAXVOICES; v++)
535                                 llgrps(mainll_p->u.staff_p,
536                                        mainll_p->u.staff_p->groups_p[v], place);
537                 }
538         }
539 }
540 \f
541 /*
542  * Name:        llgrps()
543  *
544  * Abstract:    Set up rectangles for note and rest groups.
545  *
546  * Returns:     void
547  *
548  * Description: This function puts rectangles into rectab for all groups in
549  *              this measure of this voice, for groups consisting of notes or
550  *              rests.
551  */
552
553 static void
554 llgrps(staff_p, first_p, place)
555
556 struct STAFF *staff_p;          /* point to the staff */
557 struct GRPSYL *first_p;         /* point to first group */
558 int place;                      /* above or below? */
559
560 {
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 */
566
567
568         /*
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.
572          */
573         for (gs_p = first_p; gs_p != 0; gs_p = gs_p->next) {
574                 if (gs_p->grpcont == GC_SPACE)
575                         continue;
576
577                 if (gs_p->grpcont == GC_REST && is_tab_staff(gs_p->staffno))
578                         continue;
579
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
585                 )) {
586                         /*
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
591                          * to be printed.
592                          */
593                         (void)mrnum(staff_p, &mx, &my_offset, &mheight,
594                                         &mwidth);
595                         rectab[reclim].w = mx;
596                         rectab[reclim].e = mx + mwidth;
597                         rectab[reclim].n = my_offset + mheight;
598                         rectab[reclim].s = 0;
599
600                         inc_reclim();
601                         continue;
602                 }
603
604                 /* for "below", no rectangles are needed for multirests */
605                 if (gs_p->basictime < -1)
606                         continue;
607
608                 /*
609                  * We have a normal note or rest group.  Make a rectangle for
610                  * it, making sure it reaches the center staff line.
611                  */
612                 rectab[reclim].w = gs_p->c[AW];
613                 rectab[reclim].e = gs_p->c[AE];
614
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);
621                 }
622
623                 inc_reclim();
624
625                 /* if a clef precedes this group, make a rectangle for it */
626                 if (gs_p->clef != NOCLEF) {
627                         float north, south;     /* clef coords */
628
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;
635
636                         inc_reclim();
637                 }
638
639                 /*
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.
650                  */
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];
655
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 *
674                                                 (radius + Stdpad);
675                                         inc_reclim();
676                                 }
677
678                                 if (note_p->accidental == '\0')
679                                         continue;
680
681                                 /* this note has an acc; create a rectangle */
682                                 accdimen(note_p, &asc, &des, &wid);
683                                 asc *= Staffscale;
684                                 des *= Staffscale;
685                                 wid *= Staffscale;
686
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;
691
692                                 inc_reclim();
693                         }
694                 }
695         }
696 }
697 \f
698 /*
699  * Name:        dobeamalt()
700  *
701  * Abstract:    Set up rectangles for beams and alternation bars.
702  *
703  * Returns:     void
704  *
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.
708  */
709
710 static void
711 dobeamalt(start_p, s, place)
712
713 struct MAINLL *start_p;         /* FEED at the start of this score */
714 int s;                          /* staff number */
715 int place;                      /* above or below? */
716
717 {
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 */
721
722
723         debug(32, "dobeamalt file=%s line=%d s=%d place=%d", start_p->inputfile,
724                         start_p->inputlineno, s, place);
725         /*
726          * Loop through this score's part of the MLL.
727          */
728         for (mainll_p = start_p->next; mainll_p != 0 &&
729                         mainll_p->str != S_FEED; mainll_p = mainll_p->next) {
730                 /*
731                  * Whenever we find a structure for this staff (another
732                  * measure of this staff), loop through its voices.
733                  */
734                 if (mainll_p->str == S_STAFF &&
735                                 mainll_p->u.staff_p->staffno == s) {
736
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) {
740                                         /*
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
749                                          * already.
750                                          */
751                                         if (gs_p->grpcont == GC_NOTES &&
752                                             gs_p->grpvalue == GV_NORMAL &&
753                                             gs_p->beamloc == STARTITEM &&
754                                             gs_p->beamto == CS_SAME) {
755
756                                                 if (place == PL_ABOVE &&
757                                                     gs_p->stemdir == UP ||
758                                                     place == PL_BELOW &&
759                                                     gs_p->stemdir == DOWN)
760
761                                                         onebeamalt(gs_p);
762                                         }
763                                 }
764                         }
765                 }
766         }
767 }
768 \f
769 /*
770  * Name:        onebeamalt()
771  *
772  * Abstract:    Set up rectangle(s) for one beam or alternation bar.
773  *
774  * Returns:     void
775  *
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
782  *              staff line.
783  */
784
785 static void
786 onebeamalt(gs_p)
787
788 struct GRPSYL *gs_p;            /* initially points to first group */
789
790 {
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 */
794
795
796         /*
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.
804          */
805         x1 = gs_p->c[AX];
806         y1 = getstemendvert(gs_p);
807
808         while (gs_p != 0 && (gs_p->grpvalue == GV_ZERO ||
809                              gs_p->beamloc != ENDITEM))
810                 gs_p = gs_p->next;
811         if (gs_p == 0)
812                 pfatal("beam or alt group has no ENDITEM");
813
814         x2 = gs_p->c[AX];
815         y2 = getstemendvert(gs_p);
816
817         stemshift = getstemshift(gs_p);
818
819         if (gs_p->basictime >= 2) {
820                 /* the groups have stems (if first one does, others must too)*/
821                 if (gs_p->stemdir == UP) {
822                         x1 += stemshift;
823                         x2 += stemshift;
824                 } else {
825                         x1 -= stemshift;
826                         x2 -= stemshift;
827                 }
828         }
829
830         /* make zero or more rectangles for this beam/alt */
831         linerects(x1, y1, x2, y2, gs_p->stemdir, halfstaffhi(gs_p->staffno));
832 }
833 \f
834 /*
835  * Name:        getstemendvert()
836  *
837  * Abstract:    Find the vertical coord of the end of a stem.
838  *
839  * Returns:     void
840  *
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).
845  */
846
847 static double
848 getstemendvert(gs_p)
849
850 struct GRPSYL *gs_p;    /* the group in question */
851
852 {
853         double y;       /* the answer */
854
855
856         if (gs_p->nwith == 0 || gs_p->normwith == YES) {
857                 /*
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.
860                  */
861                 y = gs_p->stemdir == UP ? gs_p->c[RN] : gs_p->c[RS];
862         } else {
863                 /*
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.
867                  */
868                 if (gs_p->stemdir == UP)
869                         y = gs_p->notelist[ gs_p->nnotes - 1 ].c[RY] +
870                                         gs_p->stemlen;
871                 else
872                         y = gs_p->notelist[ 0 ].c[RY] - gs_p->stemlen;
873         }
874
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);
879                 } else {
880                         y -= (W_WIDE * Stdpad / 2.0);
881                 }
882         }
883
884         return (y);
885 }
886 \f
887 /*
888  * Name:        linerects()
889  *
890  * Abstract:    Set up rectangle(s) to contain a (possibly) slanted line.
891  *
892  * Returns:     void
893  *
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.
900  */
901
902 static void
903 linerects(x1, y1, x2, y2, side, halfstaff)
904
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 */
909
910 {
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 */
914
915
916         /* if line is within staff, no need for any rectangles */
917         if (fabs(y1) < halfstaff && fabs(y2) < halfstaff)
918                 return;
919
920         /*
921          * If this beam/alt is level, make one big rectangle, and get out.
922          */
923         if (y1 == y2) {
924                 rectab[reclim].w = x1;
925                 rectab[reclim].e = x2;
926                 if (side == UP) {
927                         rectab[reclim].n = y1;
928                         rectab[reclim].s = 0;
929                 } else {
930                         rectab[reclim].n = 0;
931                         rectab[reclim].s = y1;
932                 }
933                 inc_reclim();
934                 return;
935         }
936
937         /*
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.
942          */
943         slope = (y1 - y2) / (x1 - x2);
944         yintercept = y1 - slope * x1;
945         deltax = Stepsize / fabs(slope);
946
947         for (leftx = x1; leftx < x2; leftx += deltax) {
948                 rightx = MIN(x2, leftx + deltax);
949                 rectab[reclim].w = leftx;
950                 rectab[reclim].e = rightx;
951                 if (side == UP) {
952                         rectab[reclim].n = slope * (slope > 0 ? rightx : leftx)
953                                         + yintercept;
954                         rectab[reclim].s = 0;
955                 } else {
956                         rectab[reclim].n = 0;
957                         rectab[reclim].s = slope * (slope > 0 ? leftx : rightx)
958                                         + yintercept;
959                 }
960                 inc_reclim();
961         }
962 }
963 \f
964 /*
965  * Name:        docurve()
966  *
967  * Abstract:    Get point list and set up rectangles for tie/slur/bend/phrase.
968  *
969  * Returns:     void
970  *
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.
976  */
977
978 static void
979 docurve(start_p, s, place, do_which)
980
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 */
985
986 {
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 */
990
991
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);
995
996         /*
997          * Loop through this score's part of the MLL, looking for matching
998          * staffs.
999          */
1000         for (mainll_p = start_p->next; mainll_p != 0 &&
1001                         mainll_p->str != S_FEED; mainll_p = mainll_p->next) {
1002
1003                 if (mainll_p->str != S_STAFF ||
1004                                 mainll_p->u.staff_p->staffno != s)
1005                         continue;
1006
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){
1010
1011                         switch (stuff_p->stuff_type) {
1012                         case ST_TIESLUR:
1013                         case ST_TABSLUR:
1014                         case ST_BEND:
1015                         case ST_PHRASE:
1016                                 break;          /* docurve works on these */
1017                         default:
1018                                 continue;       /* for some other function */
1019                         }
1020
1021                         /*
1022                          * If we are to do phrases and this is not a phrase, or
1023                          * vice versa, skip this.
1024                          */
1025                         if ((do_which == DO_PHRASE) !=
1026                             (stuff_p->stuff_type == ST_PHRASE))
1027                                 continue;
1028
1029                         /*
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".
1033                          */
1034                         if (place == PL_ABOVE) {
1035                                 switch (stuff_p->stuff_type) {
1036                                 case ST_TIESLUR:
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,
1041                                                         mainll_p) == YES) {
1042                                                 break;
1043                                         }
1044                                         tieslur_points(mainll_p, stuff_p);
1045                                         break;
1046                                 case ST_TABSLUR:
1047                                         tabslur_points(mainll_p, stuff_p);
1048                                         break;
1049                                 case ST_BEND:
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,
1054                                                         mainll_p) == YES) {
1055                                                 break;
1056                                         }
1057                                         bend_points(mainll_p, stuff_p);
1058                                         break;
1059                                 case ST_PHRASE:
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,
1064                                                         mainll_p) == YES) {
1065                                                 break;
1066                                         }
1067                                         phrase_points(mainll_p, stuff_p);
1068                                         break;
1069                                 }
1070                         }
1071
1072                         /*
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.
1077                          */
1078                         if (stuff_p->crvlist_p != 0) {
1079                                 curverect(s, stuff_p, halfstaff);
1080                         }
1081                 }
1082         }
1083 }
1084 \f
1085 /*
1086  * Name:        curverect()
1087  *
1088  * Abstract:    Put rectangles in rectab for a tie, slur, bend, or phrase.
1089  *
1090  * Returns:     void
1091  *
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().
1096  */
1097
1098 static void
1099 curverect(s, stuff_p, halfstaff)
1100
1101 int s;                          /* staff number */
1102 struct STUFF *stuff_p;          /* the curve's STUFF */
1103 double halfstaff;               /* half the staff height */
1104
1105 {
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 */
1110
1111
1112         /*
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.
1118          */
1119         for (point_p = stuff_p->crvlist_p; point_p->next != 0;
1120                         point_p = point_p->next) {
1121
1122                 x1 = point_p->x;
1123                 y1 = point_p->y;
1124                 x2 = point_p->next->x;
1125                 y2 = point_p->next->y;
1126
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);
1131                 } else {
1132                         /* a real curve */
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);
1137                 }
1138         }
1139 }
1140 \f
1141 /*
1142  * Name:        curvepiecerect()
1143  *
1144  * Abstract:    Put rects in rectab for a piece of a tie, slur, bend, or phrase.
1145  *
1146  * Returns:     void
1147  *
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.
1151  */
1152
1153 static void
1154 curvepiecerect(x1, y1, x2, y2, halfstaff)
1155
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 */
1159
1160 {
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 */
1164
1165
1166         /* if whole piece is within the staff, no rectangles are needed */
1167         if (fabs(y1) < halfstaff && fabs(y2) < halfstaff)
1168                 return;
1169
1170         /*
1171          * If this piece is level, make 1 big rectangle, and continue.
1172          */
1173         if (y1 == y2) {
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);
1178                 inc_reclim();
1179                 return;
1180         }
1181
1182         /*
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.
1190          */
1191         slope = (y1 - y2) / (x1 - x2);
1192         yintercept = y1 - slope * x1;
1193         deltax = Stepsize / fabs(slope);
1194
1195         for (leftx = x1; leftx < x2; leftx += deltax) {
1196                 rightx = MIN(x2, leftx + deltax);
1197
1198                 rectab[reclim].w = leftx;
1199                 rectab[reclim].e = rightx;
1200
1201                 /*
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.
1208                  */
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;
1213
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;
1219
1220                 inc_reclim();
1221         }
1222 }
1223 \f
1224 /*
1225  * Name:        dotuplet()
1226  *
1227  * Abstract:    Set up rectangles for tuplet brackets.
1228  *
1229  * Returns:     void
1230  *
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.
1234  */
1235
1236
1237 static void
1238 dotuplet(start_p, s, place)
1239
1240 struct MAINLL *start_p;         /* FEED at the start of this score */
1241 int s;                          /* staff number */
1242 int place;                      /* above or below? */
1243
1244 {
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 */
1248
1249
1250         debug(32, "dotuplet file=%s line=%d s=%d place=%d", start_p->inputfile,
1251                         start_p->inputlineno, s, place);
1252
1253         /* tuplet brackets are never printed on tablature staffs */
1254         if (is_tab_staff(s))
1255                 return;
1256
1257         /*
1258          * Loop through this score's part of the MLL.
1259          */
1260         for (mainll_p = start_p->next; mainll_p != 0 &&
1261                         mainll_p->str != S_FEED; mainll_p = mainll_p->next) {
1262                 /*
1263                  * Whenever we find a structure for this staff (another
1264                  * measure of this staff), loop through its voices.
1265                  */
1266                 if (mainll_p->str == S_STAFF &&
1267                                 mainll_p->u.staff_p->staffno == s) {
1268
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) {
1272                                         /*
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
1277                                          * rectab.
1278                                          */
1279                                         if ((gs_p->tuploc == STARTITEM ||
1280                                              gs_p->tuploc == LONEITEM) &&
1281                                             gs_p->printtup != PT_NEITHER) {
1282
1283                                                 if (tupdir(gs_p, mainll_p->u.
1284                                                         staff_p) == place)
1285
1286                                                         onetuplet(mainll_p->u.
1287                                                         staff_p, gs_p, place);
1288                                         }
1289                                 }
1290                         }
1291                 }
1292         }
1293 }
1294 \f
1295 /*
1296  * Name:        onetuplet()
1297  *
1298  * Abstract:    Set up rectangle(s) for one tuplet bracket or number.
1299  *
1300  * Returns:     void
1301  *
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.
1310  */
1311
1312 static void
1313 onetuplet(staff_p, start_p, place)
1314
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? */
1318
1319 {
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 */
1326
1327
1328         /*
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.
1333          */
1334         x1 = start_p->c[AX];
1335         y1 = (place == PL_ABOVE ? start_p->c[RN] : start_p->c[RS])
1336                         + start_p->tupextend;
1337
1338         for (gs_p = start_p; gs_p != 0 && (gs_p->grpvalue == GV_ZERO ||
1339                         gs_p->tuploc != ENDITEM && gs_p->tuploc != LONEITEM);
1340                         gs_p = gs_p->next)
1341                 ;
1342         if (gs_p == 0)
1343                 pfatal("tuplet has no ENDITEM");
1344
1345         x2 = gs_p->c[AX];
1346         y2 = (place == PL_ABOVE ? gs_p->c[RN] : gs_p->c[RS]) + gs_p->tupextend;
1347
1348         /*
1349          * If there is not going to be a bracket, create one rectangle for the
1350          * tuplet number, and return.
1351          */
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;
1358
1359                 inc_reclim();
1360                 return;
1361         }
1362
1363         /* there is going to be a bracket; extend x coords to reach to end */
1364         stemshift = getstemshift(gs_p);
1365
1366         x1 -= stemshift;
1367         x2 += stemshift;
1368
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));
1372 }
1373 \f
1374 /*
1375  * Name:        domiscstuff()
1376  *
1377  * Abstract:    Set up rectangles and vert coords for miscellaneous STUFF.
1378  *
1379  * Returns:     void
1380  *
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.
1386  */
1387
1388 static void
1389 domiscstuff(start_p, s, place, do_which)
1390
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 */
1395
1396 {
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 */
1404
1405
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);
1408         /*
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".
1413          */
1414         for (mainll_p = start_p->next; mainll_p != 0 &&
1415                         mainll_p->str != S_FEED; mainll_p = mainll_p->next) {
1416
1417                 if (mainll_p->str != S_STAFF ||
1418                                 mainll_p->u.staff_p->staffno != s) {
1419                         continue;
1420                 }
1421
1422                 for (stuff_p = mainll_p->u.staff_p->stuff_p;
1423                                 stuff_p != 0; stuff_p = stuff_p->next) {
1424
1425                         if (stuff_p->place != place) {
1426                                 continue;
1427                         }
1428
1429                         stype = stuff_p->stuff_type;
1430
1431                         /* if wrong type for this pass, exit */
1432                         if (stype == ST_MUSSYM) {
1433                                 if ((do_which & (1L << MK_MUSSYM)) == 0)
1434                                         continue;
1435                         } else if (stype == ST_OCTAVE) {
1436                                 if ((do_which & (1L << MK_OCTAVE)) == 0)
1437                                         continue;
1438                         } else if (stype != ST_PHRASE &&
1439                                         stuff_p->modifier == TM_DYN) {
1440                                 if ((do_which & (1L << MK_DYN)) == 0)
1441                                         continue;
1442                         } else if (stype != ST_PHRASE &&
1443                                         IS_CHORDLIKE(stuff_p->modifier)) {
1444                                 if ((do_which & (1L << MK_CHORD)) == 0)
1445                                         continue;
1446                         } else if (IS_TEXT(stype)) {
1447                                 if ((do_which & (1L << MK_OTHERTEXT)) == 0)
1448                                         continue;
1449                         }
1450
1451                         /*
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.
1455                          */
1456                         /* avoid 'used before set' warning */
1457                         high = lowpart = 0.0;
1458
1459                         /* handle various types differently */
1460                         switch (stype) {
1461                         case ST_PEDAL:
1462                         case ST_PHRASE:
1463                         case ST_TIESLUR:
1464                         case ST_TABSLUR:
1465                         case ST_BEND:
1466                         case ST_MIDI:
1467                                 /* don't handle these types here; */
1468                                 /* they have their own subroutines */
1469                                 continue;
1470
1471                         case ST_OCTAVE:
1472                         case ST_ROM:
1473                         case ST_BOLD:
1474                         case ST_ITAL:
1475                         case ST_BOLDITAL:
1476                         case ST_MUSSYM:
1477                                 /* high is string's height */
1478                                 high = strheight( stuff_p->string);
1479                                 lowpart = strdescent( stuff_p->string);
1480
1481                                 /*
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".
1487                                  */
1488                                 if (stuff_p->modifier == TM_CHORD && svpath(s,
1489                                 GRIDSWHEREUSED)->gridswhereused == YES) {
1490                                         struct GRID *grid_p;
1491                                         float gnorth, gsouth;
1492
1493                                         grid_p = findgrid(stuff_p->string);
1494                                         /* if none, skip this; stuff.c warned*/
1495                                         if (grid_p == 0)
1496                                                 break;
1497
1498                                         gridsize(grid_p, stuff_p->all ? 0 :
1499                                                 mainll_p->u.staff_p->staffno,
1500                                                 &gnorth, &gsouth,
1501                                                 (float *)0, (float *)0);
1502
1503                                         high += gnorth - gsouth;
1504                                         lowpart += gnorth - gsouth;
1505                                 }
1506                                 break;
1507
1508                         case ST_CRESC:
1509                         case ST_DECRESC:
1510                                 /* height depends on length */
1511                                 len = stuff_p->c[AE] - stuff_p->c[AW];
1512
1513                                 if (len < 0.5)
1514                                         high = 2.00 * STEPSIZE + 2 * STDPAD;
1515                                 else if (len < 2.0)
1516                                         high = 2.67 * STEPSIZE + 2 * STDPAD;
1517                                 else
1518                                         high = 3.33 * STEPSIZE + 2 * STDPAD;
1519
1520                                 if (stuff_p->all)
1521                                         high *= Score.staffscale;
1522                                 else
1523                                         high *= Staffscale;
1524
1525                                 lowpart = high / 2;
1526
1527                                 break;
1528
1529                         default:
1530                                 pfatal("unknown stuff type (%d)", stype);
1531                         }
1532
1533                         /*
1534                          * Now find "dist", the minimum distance it should be
1535                          * put from the staff.
1536                          */
1537                         if (stuff_p->dist_usage == SD_NONE) {
1538                                 /*
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.
1545                                  */
1546                                 /* if "dyn", fake to use same logic as cresc */
1547                                 if (stuff_p->modifier == TM_DYN)
1548                                         stype = ST_CRESC;
1549                                 switch (stype) {
1550                                 case ST_ROM:
1551                                 case ST_BOLD:
1552                                 case ST_ITAL:
1553                                 case ST_BOLDITAL:
1554                                         if (stuff_p->all) {
1555                                                 if (IS_CHORDLIKE(
1556                                                 stuff_p->modifier)) {
1557                                                         dist =
1558                                                         halfstaffhi(s) +
1559                                                         STEPSIZE *
1560                                                         Score.staffscale *
1561                                                         Score.chorddist;
1562                                                 } else {
1563                                                         dist =
1564                                                         halfstaffhi(s) +
1565                                                         STEPSIZE *
1566                                                         Score.staffscale *
1567                                                         Score.dist;
1568                                                 }
1569                                         } else {
1570                                                 if (IS_CHORDLIKE(
1571                                                 stuff_p->modifier)) {
1572                                                         dist =
1573                                                         halfstaffhi(s) +
1574                                                         Stepsize *
1575                                                         svpath(s, CHORDDIST)->
1576                                                         chorddist;
1577                                                 } else {
1578                                                         dist =
1579                                                         halfstaffhi(s) +
1580                                                         Stepsize *
1581                                                         svpath(s, DIST)->dist;
1582                                                 }
1583                                         }
1584                                         break;
1585                                 case ST_CRESC:
1586                                 case ST_DECRESC:
1587                                         if (stuff_p->all) {
1588                                                 dist = halfstaffhi(s) +
1589                                                 STEPSIZE * Score.staffscale *
1590                                                 Score.dyndist;
1591                                         } else {
1592                                                 dist = halfstaffhi(s) +
1593                                                 Stepsize * svpath(s,
1594                                                 DYNDIST)->dyndist;
1595                                         }
1596                                         break;
1597                                 default:
1598                                         dist = 0;
1599                                         break;
1600                                 }
1601                         } else {
1602                                 /* the user specified the dist, so use that */
1603                                 if (stuff_p->all) {
1604                                         dist = halfstaffhi(s) +
1605                                                 STEPSIZE * stuff_p->dist;
1606                                 } else {
1607                                         dist = halfstaffhi(s) +
1608                                                 Stepsize * stuff_p->dist;
1609                                 }
1610                         }
1611
1612                         if (stuff_p->dist_usage == SD_FORCE) {
1613                                 /*
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.
1617                                  */
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;
1626                                 }
1627                                 rectab[reclim].e = stuff_p->c[AE];
1628                                 rectab[reclim].w = stuff_p->c[AW];
1629                                 inc_reclim();
1630                         } else {
1631                                 /*
1632                                  * Stack the usual way.  For the case of
1633                                  * "between", stackit() will ignore "dist".
1634                                  */
1635                                 stuff_p->c[RS] = stackit(stuff_p->c[AW],
1636                                         stuff_p->c[AE], high, dist, place);
1637                         }
1638
1639                         stuff_p->c[RN] = stuff_p->c[RS] + high;
1640                         stuff_p->c[RY] = stuff_p->c[RS] + lowpart;
1641                 }
1642         }
1643 }
1644 \f
1645 /*
1646  * Name:        dolyrics()
1647  *
1648  * Abstract:    Set up rectangles and vert coords for lyrics.
1649  *
1650  * Returns:     void
1651  *
1652  * Description: This function puts into rectab a rectangle for each verse in
1653  *              the "place" relationship to the given staff on this score.
1654  */
1655
1656 static void
1657 dolyrics(start_p, s, place)
1658
1659 struct MAINLL *start_p;         /* FEED at the start of this score */
1660 int s;                          /* staff number */
1661 int place;                      /* above, below, or between? */
1662
1663 {
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 */
1679
1680
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 */
1684         if (Maxverses == 0)
1685                 return;
1686
1687         /*
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.
1691          */
1692         MALLOCA(int, versenums, Maxverses);
1693
1694         /*
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.
1700          */
1701         gotverse0 = NO;
1702         gototherverse = NO;
1703         for (mainll_p = start_p->next; mainll_p != 0 &&
1704                         mainll_p->str != S_FEED; mainll_p = mainll_p->next) {
1705                 /*
1706                  * Whenever we find a structure for this staff (another
1707                  * measure of this staff), loop through its verse headcells.
1708                  */
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)
1715                                                 gotverse0 = YES;
1716                                         else
1717                                                 gototherverse = YES;
1718                                 }
1719                         }
1720                 }
1721         }
1722
1723         /* if no verses, get out now */
1724         if (gotverse0 == NO && gototherverse == 0) {
1725                 FREE(versenums);
1726                 return;
1727         }
1728
1729         /*
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.
1734          */
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) {
1740                 /*
1741                  * Whenever we find a structure for this staff (another
1742                  * measure of this staff), loop through its verse headcells.
1743                  */
1744                 if (mainll_p->str == S_STAFF &&
1745                                 mainll_p->u.staff_p->staffno == s) {
1746
1747                         staff_p = mainll_p->u.staff_p;
1748
1749                         for (n = 0; n < staff_p->nsyllists; n++) {
1750
1751                                 if (staff_p->sylplace[n] == place) {
1752                                         /*
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).
1759                                          */
1760                                         v = staff_p->syls_p[n]->vno;
1761                                         /* ignore verse 0 if others exist */
1762                                         if (v == 0 && gototherverse == YES)
1763                                                 continue;
1764                                         for (k = 0; k < vfound &&
1765                                                     v < versenums[k]; k++) {
1766                                                 ;
1767                                         }
1768                                         if (k == vfound || v > versenums[k]) {
1769                                                 for (j = vfound; j > k; j--) {
1770                                                         versenums[j] =
1771                                                         versenums[j-1];
1772                                                 }
1773                                                 versenums[k] = v;
1774                                                 vfound++;  /* found one more */
1775                                         }
1776
1777                                         /*
1778                                          * If any syl sticks out farther than
1779                                          * any previous one, extend farwest or
1780                                          * fareast.
1781                                          */
1782                                         for (gs_p = staff_p->syls_p[n];
1783                                              gs_p != 0; gs_p = gs_p->next) {
1784
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];
1789                                         }
1790                                 }
1791                         }
1792                 }
1793         }
1794
1795         /*
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.
1805          */
1806         if (place == PL_BETWEEN)
1807                 dist = 0;
1808         else
1809                 dist = halfstaffhi(s) + 2.0 * Stepsize;
1810
1811         (void)stackit(farwest - 8 * STEPSIZE, fareast + 8 * STEPSIZE, PGHEIGHT,
1812                         dist, place);
1813
1814         /*
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.
1818          */
1819         if (place == PL_BELOW)
1820                 protrude = rectab[reclim - 1].n;
1821         else
1822                 protrude = rectab[reclim - 1].s;
1823
1824         /*
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.
1828          */
1829         if (place == PL_BELOW) {        /* work downward from staff */
1830                 begin = vfound - 1;     /* first verse number */
1831                 end = -1;               /* beyond last verse number */
1832                 delta = -1;
1833         } else {        /* above and between both work upwards from bottom */
1834                 begin = 0;              /* last verse number */
1835                 end = vfound;           /* before first verse number */
1836                 delta = 1;
1837         }
1838         for (n = begin; n != end; n += delta) {
1839                 /*
1840                  * Find the farthest any syllable ascends and descends from the
1841                  * baseline of the verse.
1842                  */
1843                 getvsize(start_p, s, place, versenums[n], &maxasc, &maxdes);
1844
1845                 /*
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.
1849                  */
1850                 if (place == PL_BELOW)
1851                         baseline = protrude - maxasc;
1852                 else    /* above or between */
1853                         baseline = protrude + maxdes;
1854
1855                 /* set syllables' vertical coords; continue underscores */
1856                 setsylvert(start_p, s, place, versenums[n], baseline);
1857
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;
1863
1864         } /* for every verse */
1865
1866         /*
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.
1870          */
1871         if (gotverse0 == YES && gototherverse == YES) {
1872                 float mid;      /* RY of the middle of the normal verses */
1873                 struct RECTAB rec;      /* one rectangle */
1874
1875                 /* get ascent and descent of verse 0 */
1876                 getvsize(start_p, s, place, 0, &maxasc, &maxdes);
1877
1878                 /*
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.
1884                  */
1885                 if (place == PL_BELOW) {
1886                         mid = (rectab[reclim - 1].n + protrude) / 2.0;
1887                         dist = -mid - (maxasc + maxdes) / 2.0;
1888                 } else {
1889                         mid = (protrude + rectab[reclim - 1].s) / 2.0;
1890                         dist = mid - (maxasc + maxdes) / 2.0;
1891                 }
1892
1893                 /*
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.
1897                  */
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) {
1903
1904                         if (mainll_p->str != S_STAFF ||
1905                                         mainll_p->u.staff_p->staffno != s)
1906                                 continue;
1907
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) {
1914
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];
1919                                         }
1920                                 }
1921                         }
1922                 }
1923
1924                 /*
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.
1929                  */
1930                 rectab[reclim - 1].n = rectab[reclim - 1].s = 0;
1931
1932                 /*
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".
1936                  */
1937                 baseline = stackit(farwest - 8 * STEPSIZE,
1938                         fareast + 8 * STEPSIZE, maxasc + maxdes, dist,
1939                         place == PL_BETWEEN ? PL_ABOVE : place) + maxdes;
1940
1941                 /*
1942                  * Switch verse 0's rectangle and the normal verses' so that
1943                  * the later code can always use reclim-1 for the normal.
1944                  */
1945                 rec = rectab[reclim - 2];
1946                 rectab[reclim - 2] = rectab[reclim - 1];
1947                 rectab[reclim - 1] = rec;
1948
1949                 setsylvert(start_p, s, place, 0, baseline);
1950         }
1951
1952         /*
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.
1956          */
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;
1963         }
1964
1965         FREE(versenums);
1966 }
1967 \f
1968 /*
1969  * Name:        getvsize()
1970  *
1971  * Abstract:    Get the maximum ascent and descent for a verse on a score.
1972  *
1973  * Returns:     void
1974  *
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.
1979  */
1980
1981 static void
1982 getvsize(start_p, s, place, v, maxasc_p, maxdes_p)
1983
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 */
1989
1990 {
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 */
1998
1999
2000         /*
2001          * Get the standard max ascent and descent for any syllable.
2002          */
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;
2007
2008         /*
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.
2013          */
2014         for (mainll_p = start_p->next; mainll_p != 0 && mainll_p->str
2015                                 != S_FEED; mainll_p = mainll_p->next) {
2016
2017                 if (mainll_p->str != S_STAFF ||
2018                                 mainll_p->u.staff_p->staffno != s)
2019                         continue;
2020
2021                 /* found a STAFF of the number we're dealing with */
2022                 staff_p = mainll_p->u.staff_p;
2023
2024                 /*
2025                  * See if this verse is present in this staff,
2026                  * and if so, loop through it.
2027                  */
2028                 for (k = 0; k < staff_p->nsyllists; k++) {
2029
2030                         if (staff_p->sylplace[k] == place &&
2031                                         staff_p->syls_p[k]->vno == v) {
2032
2033                                 for (gs_p = staff_p->syls_p[k]; gs_p != 0;
2034                                                 gs_p = gs_p->next) {
2035                                         /*
2036                                          * If asc or des is greater
2037                                          * for this syl, save it.
2038                                          */
2039                                         asc = strascent(gs_p->syl);
2040
2041                                         des = strdescent(gs_p->syl);
2042
2043                                         if (asc > *maxasc_p)
2044                                                 *maxasc_p = asc;
2045                                         if (des > *maxdes_p)
2046                                                 *maxdes_p = des;
2047                                 }
2048
2049                                 /* no need to look any more */
2050                                 break;
2051                         }
2052                 }
2053         } /* for every MLL stucture in score */
2054 }
2055 \f
2056 /*
2057  * Name:        setsylvert()
2058  *
2059  * Abstract:    Set the maximum ascent and descent for a verse on a score.
2060  *
2061  * Returns:     void
2062  *
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.
2067  */
2068
2069 static void
2070 setsylvert(start_p, s, place, v, baseline)
2071
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 */
2077
2078 {
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 */
2085
2086
2087         /*
2088          * Loop through all these syllables as before, setting their relative
2089          * vertical coords.
2090          */
2091         lastgs_p = 0;           /* set later to last nonnull syl, if exists */
2092         laststaff_p = 0;        /* set later to staff containing lastgs_p */
2093
2094         for (mainll_p = start_p->next; mainll_p != 0 && mainll_p->str
2095                                 != S_FEED; mainll_p = mainll_p->next) {
2096
2097                 if (mainll_p->str != S_STAFF ||
2098                                 mainll_p->u.staff_p->staffno != s)
2099                         continue;
2100
2101                 /* found a STAFF of the number we're dealing with */
2102                 staff_p = mainll_p->u.staff_p;
2103
2104                 /*
2105                  * See if this verse is present in this staff,
2106                  * and if so, loop through it.
2107                  */
2108                 for (k = 0; k < staff_p->nsyllists; k++) {
2109
2110                         if (staff_p->sylplace[k] == place &&
2111                                         staff_p->syls_p[k]->vno == v) {
2112
2113                                 for (gs_p = staff_p->syls_p[k]; gs_p != 0;
2114                                                 gs_p = gs_p->next) {
2115
2116                                         if (gs_p->syl == 0) {
2117                                                 continue;
2118                                         }
2119
2120                                         gs_p->c[RY] = baseline;
2121
2122                                         gs_p->c[RN] = baseline
2123                                                 + strascent(gs_p->syl);
2124
2125                                         gs_p->c[RS] = baseline
2126                                                 - strdescent(gs_p->syl);
2127
2128                                         /* remember last nonnull syl */
2129                                         if (gs_p->syl[0] != '\0') {
2130                                                 lastgs_p = gs_p;
2131                                                 laststaff_p = mainll_p;
2132                                         }
2133                                 }
2134                         }
2135                 }
2136         } /* for every MLL stucture in score */
2137
2138         /*
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.
2144          */
2145         if (lastgs_p != 0 && has_extender(lastgs_p->syl))
2146                 cont_extender(laststaff_p, place, v);
2147 }
2148 \f
2149 /*
2150  * Name:        dopedal()
2151  *
2152  * Abstract:    Set a rectangle for pedal marks, if there are any.
2153  *
2154  * Returns:     void
2155  *
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.
2159  */
2160
2161 static void
2162 dopedal(start_p, s)
2163
2164 struct MAINLL *start_p;         /* FEED at the start of this score */
2165 int s;                          /* staff number */
2166
2167 {
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 */
2175
2176
2177         debug(32, "dopedal file=%s line=%d s=%d", start_p->inputfile,
2178                         start_p->inputlineno, s);
2179         /*
2180          * Find the greatest protrusion of any currently existing rectangle.
2181          */
2182         protrude = 0;
2183         for (k = 0; k < reclim; k++) {
2184                 if (rectab[k].s < protrude)
2185                         protrude = rectab[k].s;
2186         }
2187
2188         lowpoint = 0;
2189
2190         /*
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.
2194          */
2195         for (mainll_p = start_p->next; mainll_p != 0 &&
2196                         mainll_p->str != S_FEED; mainll_p = mainll_p->next) {
2197
2198                 if (mainll_p->str != S_STAFF ||
2199                                 mainll_p->u.staff_p->staffno != s)
2200                         continue;
2201
2202                 for (stuff_p = mainll_p->u.staff_p->stuff_p;
2203                                 stuff_p != 0; stuff_p = stuff_p->next) {
2204
2205                         if (stuff_p->stuff_type != ST_PEDAL)
2206                                 continue;
2207
2208                         /*
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.
2215                          */
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);
2223                         }
2224                         if (stuff_p->all) {
2225                                 asc *= Score.staffscale;
2226                                 hi  *= Score.staffscale;
2227                         } else {
2228                                 asc *= Staffscale;
2229                                 hi  *= Staffscale;
2230                         }
2231                         stuff_p->c[RY] = protrude - asc;
2232                         stuff_p->c[RS] = protrude - hi;
2233
2234                         if (stuff_p->c[RS] < lowpoint)
2235                                 lowpoint = stuff_p->c[RS];
2236                 }
2237         }
2238
2239         /*
2240          * If we found pedal mark(s), put one big rectangle in rectab, spanning
2241          * the width of the page.
2242          */
2243         if (lowpoint < 0) {
2244                 rectab[reclim].n = protrude;
2245                 rectab[reclim].s = lowpoint;
2246                 rectab[reclim].w = 0;
2247                 rectab[reclim].e = PGWIDTH;
2248
2249                 inc_reclim();
2250         }
2251 }
2252 \f
2253 /*
2254  * Name:        doendings()
2255  *
2256  * Abstract:    Set up rectangles and vert coords for ending marks.
2257  *
2258  * Returns:     void
2259  *
2260  * Description: This function puts into rectab rectangles for ending marks.
2261  *              Also, MARKCOORD structures get linked to BARs for them.
2262  */
2263
2264 static void
2265 doendings(start_p, s)
2266
2267 struct MAINLL *start_p;         /* FEED at the start of this score */
2268 int s;                          /* staff number */
2269
2270 {
2271         struct MAINLL *mainll_p;/* point along main linked list */
2272         struct BAR *bar_p;      /* point at a bar or pseudobar on this score */
2273
2274
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)
2279                 return;
2280
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;
2284
2285         /*
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.
2288          */
2289         if (bar_p->endingloc != NOITEM) {
2290                 /*
2291                  * Search forward for the end of this ending (or following
2292                  * contiguous ones), or the end of the score, whichever comes
2293                  * first.
2294                  */
2295                 while ( ! (mainll_p->str == S_BAR &&
2296                                         mainll_p->u.bar_p->endingloc == ENDITEM)
2297                                 && mainll_p->str != S_FEED) {
2298
2299                         mainll_p = mainll_p->next;
2300                 }
2301
2302                 /* handle ending(s) from start to this bar or feed */
2303                 storeend(start_p, mainll_p, s);
2304
2305                 /* if feed, there's nothing more to look for */
2306                 if (mainll_p->str == S_FEED)
2307                         return;
2308
2309                 /* point after this bar at end of this ending(s) */
2310                 mainll_p = mainll_p->next;
2311         }
2312
2313         /*
2314          * Search the rest of the score for contiguous groups of endings.
2315          */
2316         while (mainll_p != 0 && mainll_p->str != S_FEED) {
2317
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)
2323                         return;
2324
2325                 /*
2326                  * We found another bar.  If it isn't associated with an
2327                  * ending, point beyond it and continue to go look for the
2328                  * next bar.
2329                  */
2330                 if (mainll_p->u.bar_p->endingloc == NOITEM) {
2331                         mainll_p = mainll_p->next;
2332                         continue;
2333                 }
2334
2335                 /*
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.
2339                  */
2340                 start_p = mainll_p;
2341                 while ( ! (mainll_p->str == S_BAR &&
2342                                         mainll_p->u.bar_p->endingloc == ENDITEM)
2343                                 && mainll_p->str != S_FEED) {
2344
2345                         mainll_p = mainll_p->next;
2346                 }
2347
2348                 /* handle ending(s) from start to this bar or feed */
2349                 storeend(start_p, mainll_p, s);
2350
2351                 /* if feed, there's nothing more to look for */
2352                 if (mainll_p->str == S_FEED)
2353                         return;
2354
2355                 /* point after this bar at end of this ending */
2356                 mainll_p = mainll_p->next;
2357         }
2358 }
2359 \f
2360 /*
2361  * Name:        storeend()
2362  *
2363  * Abstract:    Set up rectangles and vert coords for contiguous endings.
2364  *
2365  * Returns:     void
2366  *
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.
2375  */
2376
2377 static void
2378 storeend(start_p, end_p, s)
2379
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 */
2383
2384 {
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 */
2390
2391
2392         /*
2393          * Find the west and east boundaries of the ending(s).
2394          */
2395         if (start_p->str == S_FEED)
2396                 west = start_p->next->u.clefsig_p->bar_p->c[AX]; /* pseudobar */
2397         else
2398                 west = start_p->u.bar_p->c[AX];         /* normal bar */
2399
2400         if (end_p->str == S_FEED)
2401                 east = PGWIDTH - eff_rightmargin(end_p); /* end of score */
2402         else
2403                 east = end_p->u.bar_p->c[AX];           /* normal bar */
2404
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);
2407
2408         /*
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.
2412          */
2413         rectab[reclim].n = south + ENDINGHEIGHT;
2414         rectab[reclim].s = 0;
2415         rectab[reclim].e = east;
2416         rectab[reclim].w = west;
2417         inc_reclim();
2418
2419         /*
2420          * If the pseudobar has an ending, calloc a markcoord structure and put
2421          * it in the pseudobar's linked list of them.
2422          */
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;
2429                 mark_p->ry = south;
2430         }
2431
2432         /*
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.
2436          */
2437         for (mainll_p = start_p; mainll_p != end_p; mainll_p = mainll_p->next) {
2438                 if (mainll_p->str != S_BAR)
2439                         continue;
2440                 bar_p = mainll_p->u.bar_p;
2441                 if (bar_p->endingloc != STARTITEM)
2442                         continue;
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;
2447                 mark_p->ry = south;
2448         }
2449 }
2450 \f
2451 /*
2452  * Name:        dorehears()
2453  *
2454  * Abstract:    Set up rectangles and vert coords for rehearsal marks.
2455  *
2456  * Returns:     void
2457  *
2458  * Description: This function puts into rectab rectangles for rehearsal marks.
2459  *              Also, MARKCOORD structures get linked to BARs for them.
2460  */
2461
2462 static void
2463 dorehears(start_p, s)
2464
2465 struct MAINLL *start_p;         /* FEED at the start of this score */
2466 int s;                          /* staff number */
2467
2468 {
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 */
2478
2479
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)
2484                 return;
2485
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;
2489
2490         /* if there's a rehearsal mark at the pseudobar, note that fact */
2491         if (bar_p->reh_type != REH_NONE)
2492                 dopseudo = YES;
2493         else
2494                 dopseudo = NO;
2495
2496         /*
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.
2499          */
2500         for ( ; mainll_p != 0 && mainll_p->str != S_FEED;
2501                                 mainll_p = mainll_p->next) {
2502
2503                 if (dopseudo == YES || mainll_p->str == S_BAR &&
2504                                        mainll_p->u.bar_p->reh_type != REH_NONE){
2505                         if (dopseudo == YES)
2506                                 dopseudo = NO;
2507                         else
2508                                 bar_p = mainll_p->u.bar_p;
2509
2510                         /*
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.
2515                          */
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);
2520
2521                         if (bar_p->dist_usage == SD_NONE) {
2522                                 /* get the usual dist */
2523                                 dist = svpath(s, DIST)->dist;
2524                         } else {
2525                                 /* override with this bar's dist */
2526                                 dist = bar_p->dist;
2527                         }
2528                         /* convert to inches from center of staff */
2529                         dist = halfstaffhi(s) + STEPSIZE * dist;
2530
2531                         if (bar_p->dist_usage == SD_FORCE) {
2532                                 /*
2533                                  * The user is forcing this dist, so don't
2534                                  * stack; just put it there.
2535                                  */
2536                                 south = dist;
2537                                 rectab[reclim].n = south + height;
2538                                 rectab[reclim].s = south;
2539                                 rectab[reclim].e = east;
2540                                 rectab[reclim].w = west;
2541                                 inc_reclim();
2542                         } else {
2543                                 /* stack the usual way */
2544                                 south = stackit(west, east, height, dist,
2545                                                 PL_ABOVE);
2546                         }
2547
2548                         /*
2549                          * Allocate and link a MARKCOORD, and put the necessary
2550                          * info in it.
2551                          */
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);
2557                 }
2558         }
2559 }
2560 \f
2561 /*
2562  * Name:        stackit()
2563  *
2564  * Abstract:    Place a rectangle and add it to rectab.
2565  *
2566  * Returns:     south boundary of the new rectangle
2567  *
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.
2572  */
2573
2574 static double
2575 stackit(west, east, height, dist, place)
2576
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? */
2582
2583 {
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 */
2588
2589
2590         /*
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
2596          * as possible.
2597          */
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;
2602                 else
2603                         rectab[j].relevant = YES;
2604         }
2605
2606         /*
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.
2610          */
2611         north = south = 0.0;    /* prevent useless 'used before set' warning */
2612         switch (place) {
2613         case PL_BELOW:
2614                 /* work downward from staff, allowing "dist" distance */
2615                 north = -dist;
2616                 south = north - height;
2617                 break;
2618         case PL_ABOVE:
2619                 /* work upward from staff, allowing "dist" distance */
2620                 south = dist;
2621                 north = south + height;
2622                 break;
2623         case PL_BETWEEN:
2624                 /* work upward from baseline */
2625                 south = 0;
2626                 north = height;
2627                 break;
2628         }
2629
2630         /*
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.
2635          */
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;
2641                         else
2642                                 rectab[j].tried = NO;
2643                 }
2644         }
2645
2646         /*
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.
2651          */
2652         for (;;) {
2653                 overlap = NO;
2654                 for (j = 0; j < reclim; j++) {
2655                         /* ignore ones too far east or west */
2656                         if (rectab[j].relevant == NO)
2657                                 continue;
2658
2659                         /* if all south or north, okay; else overlap */
2660                         if (rectab[j].s + FUDGE <= north &&
2661                             rectab[j].n >= south + FUDGE) {
2662                                 overlap = YES;
2663                                 break;
2664                         }
2665                 }
2666
2667                 /* if no rectangle overlapped, we found a valid place */
2668                 if (overlap == NO)
2669                         break;
2670
2671                 /*
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.
2676                  */
2677                 try = -1;
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)
2681                                 continue;
2682
2683                         /*
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.
2687                          */
2688                         if (place == PL_BELOW) {
2689                                 if (try == -1 || rectab[j].s > rectab[try].s)
2690                                         try = j;
2691                         } else {
2692                                 if (try == -1 || rectab[j].n < rectab[try].n)
2693                                         try = j;
2694                         }
2695                 }
2696
2697                 if (try == -1)
2698                         pfatal("bug in stackit()");
2699
2700                 /*
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
2703                  * rectangle.
2704                  */
2705                 rectab[try].tried = YES;
2706                 if (place == PL_BELOW) {
2707                         north = rectab[try].s;
2708                         south = north - height;
2709                 } else {
2710                         south = rectab[try].n;
2711                         north = south + height;
2712                 }
2713
2714         } /* end of while loop trying positions for this rectangle */
2715
2716         /*
2717          * We found the correct position for the new rectangle.  Enter it
2718          * into rectab.
2719          */
2720         rectab[reclim].n = north;
2721         rectab[reclim].s = south;
2722         rectab[reclim].e = east;
2723         rectab[reclim].w = west;
2724
2725         inc_reclim();
2726
2727         return (south);
2728 }
2729 \f
2730 /*
2731  * Name:        inc_reclim()
2732  *
2733  * Abstract:    Increment no. of rectangles, and realloc more if we run out.
2734  *
2735  * Returns:     void
2736  *
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.
2740  */
2741
2742 static void
2743 inc_reclim()
2744 {
2745         /* when first called, relvert will have allocated this many */
2746         static int rectabsize = RECTCHUNK;
2747
2748
2749         reclim++;
2750
2751         /* if rectab[reclim] is still valid, no need to allocate more */
2752         if (reclim < rectabsize)
2753                 return;
2754
2755         /* must allocate another chunk of rectangles */
2756         rectabsize += RECTCHUNK;
2757         REALLOC(RECTAB, rectab, rectabsize);
2758 }