chiark / gitweb /
Import upstream version 5.3.
[mup] / mup / mup / absvert.c
1 /* Copyright (c) 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004,
2  * 2005, 2006 by Arkkra Enterprises */
3 /* All rights reserved */
4 /*
5  * Name:        absvert.c
6  *
7  * Description: This file contains functions for setting all absolute
8  *              vertical coordinates.
9  */
10
11 #include "defines.h"
12 #include "structs.h"
13 #include "globals.h"
14
15 /*
16  * Define the maximum number of scores that could ever fit on a page, when all
17  * staffs and scores are packed as tightly as possible.  The 8 * STEPSIZE is
18  * the height of the five lines of a staff, and the other factor in the
19  * denominator is the minimum distance between staffs or scores, whichever is
20  * smaller.  If a staff has less than 5 lines, it is still given as much space
21  * as a 5 line staff, so that's why we can use 8 * STEPSIZE here as the
22  * smallest possible staff size.
23  */
24 #define MAXSCORES       ( (int)(PGHEIGHT /                              \
25         (MINSTFSCALE * STEPSIZE * (8 + MIN(MINMINSTSEP, MINMINSCSEP)))) + 1 )
26
27 #define FUDGE   0.001   /* fudge factor for round off error */
28
29 /* determine what clef, if any, will be printed on a staff */
30 #define CLEF2PRINT(staffno)     \
31         (svpath(staffno, STAFFLINES)->printclef == SS_NORMAL ?  \
32                         svpath(staffno, CLEF)->clef : NOCLEF)
33
34 /* define amount of horz and vert padding between at-end grids */
35 #define HPADGRID        (2.0 * STEPSIZE)
36 #define VPADGRID        (2.0 * STEPSIZE)
37
38 /* maximum length of a chord name that we care about for sorting purposes */
39 #define MAXCHNAME       (100)
40
41 static void relscore P((struct MAINLL *mllfeed_p));
42 static void relstaff P((struct MAINLL *feed_p, int s1, int s2, double botoff,
43                 double betweendist));
44 static void posscores P((void));
45 static void abspage P((struct MAINLL *page_p, float cursep[], float maxsep[],
46                 float curpad[], float maxpad[], int totscores,
47                 double remheight, double y_start));
48 static void absstaff P((struct FEED *feed_p, struct STAFF *staff_p));
49 static double grids_atend P((double vertavail, int firstpage,
50                 struct FEED *mfeed_p, struct FEED *gfeed_p));
51 static int compgrids P((const void *g1_p_p, const void *g2_p_p));
52 static void proc_css P((void));
53 static void one_css P((struct STAFF *ts_p, struct STAFF *os_p,
54                 struct GRPSYL *tg_p, RATIONAL time));
55 static void horzavoid P((void));
56 static void avoidone P((struct MAINLL *mainll_p, struct GRPSYL *cssg_p,
57                 RATIONAL time));
58 static void set_csb_stems P((void));
59 static void onecsb P((struct GRPSYL *gs1_p, struct GRPSYL *gs2_p));
60 static int calcline P((struct GRPSYL *start1_p, struct GRPSYL *end1_p,
61                 struct GRPSYL *start2_p, struct GRPSYL *end2_p,
62                 struct GRPSYL *first_p, struct GRPSYL *last_p,
63                 int topdir, int botdir,
64                 float *b0_p, float *b1_p));
65 static void samedir P((struct GRPSYL *first_p, struct GRPSYL *last_p,
66                 struct GRPSYL *start1_p, struct GRPSYL *start2_p,
67                 struct GRPSYL *end1_p, float *b0_p, float *b1_p,
68                 double deflen, int one_end_forced, int slope_forced,
69                 double forced_slope));
70 static void oppodir P((struct GRPSYL *first_p, struct GRPSYL *last_p,
71                 struct GRPSYL *start1_p, struct GRPSYL *start2_p,
72                 float *b0_p, float *b1_p, double deflen, int one_end_forced,
73                 int slope_forced, double forced_slope));
74 static struct GRPSYL *nextcsb P((struct GRPSYL *gs_p));
75 static struct GRPSYL *nxtbmnote P((struct GRPSYL *gs_p, struct GRPSYL *first_p,
76                 struct GRPSYL *endnext_p));
77 \f
78 /*
79  * Name:        absvert()
80  *
81  * Abstract:    Set all absolute vertical coordinates.
82  *
83  * Returns:     void
84  *
85  * Description: This function sets all absolute vertical coordinates.  First it
86  *              calls relscore() for each score, to position the staffs in that
87  *              score relative to the score.  Then it calls posscores() to
88  *              decide how many scores to put on each page, and set all the
89  *              absolute coordinates.  Finally it completes the work for
90  *              cross staff stemming (CSS) and cross staff beaming (CSB).
91  */
92
93 void
94 absvert()
95
96 {
97         struct MAINLL *mainll_p;        /* point along main linked list */
98
99
100         debug(16, "absvert");
101         /*
102          * Find each section of the main linked list, delimited by FEEDs.  For
103          * each such section, call relscore() to fix the score internally
104          * (relative to itself, all staffs and between stuff).  Keep SSVs
105          * up to date so that we always know what the user requested
106          * separations are.
107          */
108         initstructs();                  /* clean out old SSV info */
109
110         for (mainll_p = Mainllhc_p; mainll_p != 0; mainll_p = mainll_p->next) {
111                 switch (mainll_p->str) {
112                 case S_SSV:
113                         asgnssv(mainll_p->u.ssv_p);
114                         break;
115
116                 case S_FEED:
117                         relscore(mainll_p);
118                         break;
119                 }
120         }
121
122         /*
123          * Position the scores on the pages, setting all absolute vertical
124          * coordinates.
125          */
126         posscores();
127
128         /*
129          * Process groups that have cross staff stemming, if there were any.
130          */
131         if (CSSused == YES) {
132                 proc_css();
133         }
134
135         /*
136          * Set stem lengths for groups involved in cross staff beaming, if
137          * there were any.
138          */
139         if (CSBused == YES) {
140                 set_csb_stems();
141         }
142 }
143 \f
144 /*
145  * Name:        relscore()
146  *
147  * Abstract:    Set certain relative coords to be relative to score.
148  *
149  * Returns:     void
150  *
151  * Description: This function loops through the part of the main linked list
152  *              for this score.  It adjusts the relative vertical coords of
153  *              STAFFs, and also of GRPSYLs (syllables) and STUFFs of the
154  *              things that are "between" staffs.  In the end, the STAFFs will
155  *              be relative to the score (FEED), and the between things will
156  *              be relative to the staff above them.  Yes, I suppose this
157  *              belongs in relvert.c, but relvert.c has enough work to do.
158  */
159
160 static void
161 relscore(mllfeed_p)
162
163 struct MAINLL *mllfeed_p;       /* FEED at start of this score */
164
165 {
166         struct MAINLL *mainll_p;/* point along main linked list */
167         struct STAFF *cstaff_p; /* point at current staff */
168         struct STAFF *pstaff_p; /* point at previous staff */
169         struct FEED *feed_p;    /* point at FEED structure itself */
170         float cstaffoffset;     /* current staff offset from score */
171         float staffdist;        /* dist between prev & cur staff inner lines*/
172         float halfnonbetween;   /* (staffdist - heightbetween) / 2 */
173         float betweendist;      /* from prev staff center line to base line */
174         float prevhalf;         /* half the height of previous staff */
175         float curhalf;          /* half the height of current staff */
176         float limit;            /* smallest dist allowed between inner lines */
177         float needed;           /* dist between inner lines to avoid collis */
178         int prevclef;           /* clef on the previous staff */
179         float prevscale;        /* staffscale of the previous staff */
180         float spad;             /* staffpad (inches) below previous staff */
181         float clefroom;         /* room for clefs and/or measure numbers */
182         static int first = YES; /* is this the first score in the song? */
183
184
185         debug(32, "relscore file=%s line=%d", mllfeed_p->inputfile,
186                         mllfeed_p->inputlineno);
187         feed_p = mllfeed_p->u.feed_p;
188
189         /*
190          * If this score is actually a block, all we have to do is set the
191          * relative vertical coords of the FEED.  We set RY to be the center.
192          */
193         if (mllfeed_p->next != 0 && mllfeed_p->next->str == S_BLOCKHEAD) {
194                 feed_p->c[RN] = mllfeed_p->next->u.blockhead_p->height / 2.0;
195                 feed_p->c[RY] = 0;              /* RY is always 0 */
196                 feed_p->c[RS] = -feed_p->c[RN];
197                 feed_p->lastdist = 0.0;
198                 return;
199         }
200
201         /*
202          * Find the first STAFF in this score (will be in first measure).
203          */
204         for (mainll_p = mllfeed_p->next; mainll_p != 0 &&
205                         mainll_p->str != S_FEED && mainll_p->str != S_STAFF;
206                         mainll_p = mainll_p->next)
207                 ;
208         if (mainll_p == 0 || mainll_p->str != S_STAFF)
209                 return; /* ignore items when there's a feed at end of song */
210
211         /* init variables for main loop */
212         cstaffoffset = 0;               /* top staff Y == score Y */
213         pstaff_p = 0;                   /* there is no previous staff */
214         prevclef = NOCLEF;
215         prevscale = 1.0;
216         spad = 0.0;             /* keep lint happy; will be set before used */
217
218         /*
219          * Loop through all STAFF structures in the first measure of this
220          * score.  Skip invisible ones.  cstaff_p always points at the staff
221          * we are working on, and pstaff_p always points to the previous
222          * visible staff (so is 0 while we are working on the first visible
223          * staff of the score).  For each visible staff except the first, we
224          * figure out how far down it should be from the one above it, and
225          * set its relative vertical coords relative to the score.  Also, we
226          * figure out where to put the things that are "between" this staff
227          * and the one above, and set them relative to the above staff.
228          */
229         for ( ; mainll_p->str == S_STAFF; mainll_p = mainll_p->next) {
230
231                 cstaff_p = mainll_p->u.staff_p;
232
233                 /*
234                  * If this staff is invisible, ignore it completely.
235                  */
236                 if (cstaff_p->visible == NO)
237                         continue;
238
239                 /*
240                  * If it's the first visible staff, there are no coords to set,
241                  * since its offset is 0 and the "between" objects below it
242                  * will be handled by the next loop.  Also set first and last
243                  * visible staff numbers in the FEED in this loop, and the
244                  * relative vertical coords of the score.
245                  */
246                 if (pstaff_p == 0) {
247                         /* set first visible staff number */
248                         feed_p->firstvis = cstaff_p->staffno;
249
250                         /* feed's RN is same as first visible staff's RN */
251                         feed_p->c[RN] = cstaff_p->c[RN];
252                         feed_p->c[RY] = 0;              /* RY is always 0 */
253
254                         /* these next 3 will be changed later if more staffs */
255                         feed_p->c[RS] = cstaff_p->c[RS];
256                         feed_p->lastvis = cstaff_p->staffno;
257                         feed_p->lastdist = cstaff_p->c[RY] - cstaff_p->c[RS] -
258                                 staffvertspace(cstaff_p->staffno) / 2.0;
259
260                         pstaff_p = cstaff_p;    /* previous visible staff */
261                         prevclef = CLEF2PRINT(pstaff_p->staffno);
262                         prevscale = svpath(pstaff_p->staffno, STAFFSCALE)->
263                                         staffscale;
264                         spad = svpath(pstaff_p->staffno, STAFFPAD)->staffpad
265                                 * STEPSIZE * prevscale;
266                         continue;               /* no coords to set */
267                 }
268
269                 /* set half the height of the previous and current staffs */
270                 prevhalf = staffvertspace(pstaff_p->staffno) / 2.0;
271                 curhalf = staffvertspace(cstaff_p->staffno) / 2.0;
272
273                 /*
274                  * The space needed between the bottom line of the previous
275                  * staff and the top line of the current staff to avoid
276                  * collisions is how far up from the current staff things
277                  * stick, plus how far down from the previous staff things
278                  * stick, plus the height of anything "between" the two.
279                  * To this we add spad for extra padding (overlap if negative).
280                  */
281                 needed = (cstaff_p->c[RN] - curhalf) +
282                          ((pstaff_p->c[RY] - pstaff_p->c[RS]) - prevhalf) +
283                          pstaff_p->heightbetween + spad;
284                 /*
285                  * Set the distance between those two lines to be what the
286                  * user requested, or what was calculated above as "needed",
287                  * whichever is greater.  Set halfnonbetween to be half of
288                  * this result, minus half the height of the "between" items.
289                  */
290                 /* never closer than this */
291                 limit = svpath(pstaff_p->staffno,MINSTSEP)->minstsep * STEPSIZE;
292                 clefroom = clefspace(prevclef, prevscale,
293                         CLEF2PRINT(cstaff_p->staffno),
294                         svpath(cstaff_p->staffno, STAFFSCALE)->staffscale,
295                         Score.measnum == YES && has_ending(cstaff_p->staffno)
296                         && first == NO);
297                 limit = MAX(limit, clefroom);
298
299                 staffdist = MAX(limit, needed); /* between prev & current */
300
301                 /*
302                  * Find half the room between the inner staff lines that is not
303                  * going to be used by the "between" items.  But pretend that
304                  * the "between" items are bigger by "spad" than they really
305                  * are, so that half of staffpad will go on each side of them.
306                  */
307                 halfnonbetween = (staffdist - (pstaff_p->heightbetween + spad))
308                                 / 2.0;
309
310                 /* set cstaffoffset for relative to score */
311                 cstaffoffset -= (prevhalf + staffdist + curhalf);
312
313                 /*
314                  * The "between" items are currently placed relative to a base
315                  * line that they were piled onto.  We would like to center
316                  * them between the staffs, but if one staff sticks out more
317                  * than the other, it may not be possible.  Center as close as
318                  * possible.  betweendist is how far the base line is from the
319                  * center line of the previous staff.
320                  */
321                 if ((pstaff_p->c[RY] - pstaff_p->c[RS]) - prevhalf >
322                                         halfnonbetween) {
323                         /*
324                          * The top staff sticks down far enough that we have
325                          * to put the "between" items below center.  Jam them
326                          * against the top staff.
327                          */
328                         betweendist = (pstaff_p->c[RY] - pstaff_p->c[RS]) +
329                                                 pstaff_p->heightbetween + spad;
330                 } else if (cstaff_p->c[RN] - curhalf > halfnonbetween) {
331                         /*
332                          * The bottom staff sticks up far enough that we have
333                          * to put the "between" items above center.  Jam them
334                          * against the bottom staff.
335                          */
336                         betweendist = (prevhalf + staffdist + curhalf) -
337                                                 cstaff_p->c[RN];
338                 } else {
339                         /*
340                          * There is room to center the between items.
341                          */
342                         betweendist = prevhalf + staffdist - halfnonbetween;
343                 }
344
345                 /* change baseline of padding to actual baseline */
346                 betweendist -= spad / 2.0;
347
348                 /*
349                  * For all STAFF structures of these staff numbers in this
350                  * score, change relative coords as described below.
351                  */
352                 relstaff(mllfeed_p, pstaff_p->staffno, cstaff_p->staffno,
353                                 cstaffoffset, betweendist);
354
355                 /* last loop iteration leaves right value in these variables */
356                 feed_p->lastvis = cstaff_p->staffno;
357                 feed_p->c[RS] = cstaff_p->c[RS];
358                 feed_p->lastdist = cstaff_p->c[RY] - cstaff_p->c[RS] - curhalf;
359
360                 pstaff_p = cstaff_p;
361                 prevclef = CLEF2PRINT(pstaff_p->staffno);
362                 prevscale = svpath(pstaff_p->staffno, STAFFSCALE)->staffscale;
363                 spad = svpath(pstaff_p->staffno, STAFFPAD)->staffpad
364                                 * STEPSIZE * prevscale;
365         }
366
367         first = NO;     /* next score will not be the first */
368 }
369 \f
370 /*
371  * Name:        relstaff()
372  *
373  * Abstract:    Set certain relative coords to be relative to score.
374  *
375  * Returns:     void
376  *
377  * Description: This function is given two staff structures for consecutive
378  *              visible staffs.  For all STAFF structures of these staff
379  *              numbers in this score, set the bottom staff's coords relative
380  *              to the score, and set the "between" items' coords (for what's
381  *              between top and bottom staff) relative to the top staff.
382  */
383
384 static void
385 relstaff(feed_p, s1, s2, botoff, betweendist)
386
387 struct MAINLL *feed_p;          /* pointer to FEED for this score */
388 int s1;                         /* number of top staff */
389 int s2;                         /* number of bottom staff */
390 double botoff;                  /* center line of bottom, relative to score */
391 double betweendist;             /* center line of top to base line of between*/
392
393 {
394         struct MAINLL *mainll_p;/* point along main linked list */
395         struct STAFF *staff_p;  /* pointer to a staff */
396         struct GRPSYL *syl_p;   /* pointer to a syllable */
397         struct STUFF *stuff_p;  /* pointer to stuff to draw */
398         int n;                  /* loop variable */
399
400
401         debug(32, "relstaff file=%s line=%d s1=%d s2=%d botoff=%f betweendist=%f",
402                         feed_p->inputfile, feed_p->inputlineno, s1, s2,
403                         (float)botoff, (float)betweendist);
404         /*
405          * Loop through the section of the main linked list for this score,
406          * looking for every STAFF for one of the two given staffs.
407          */
408         for (mainll_p = feed_p->next; mainll_p != 0 && mainll_p->str != S_FEED;
409                                 mainll_p = mainll_p->next) {
410
411                 if (mainll_p->str == S_STAFF &&
412                                 mainll_p->u.staff_p->staffno == s1) {
413
414                         staff_p = mainll_p->u.staff_p;
415
416                         /*
417                          * Subtract betweendist from all relative coords of
418                          * "between" items hanging off this staff, to make them
419                          * relative to this staff instead of the base line.
420                          */
421                         for (n = 0; n < staff_p->nsyllists; n++) {
422                                 if (staff_p->sylplace[n] == PL_BETWEEN) {
423                                         for (syl_p = staff_p->syls_p[n];
424                                                         syl_p != 0;
425                                                         syl_p = syl_p->next) {
426                                                 syl_p->c[RN] -= betweendist;
427                                                 syl_p->c[RY] -= betweendist;
428                                                 syl_p->c[RS] -= betweendist;
429                                         }
430                                 }
431                         }
432                         for (stuff_p = staff_p->stuff_p; stuff_p != 0;
433                                         stuff_p = stuff_p->next) {
434                                 if (stuff_p->place == PL_BETWEEN) {
435                                         stuff_p->c[RN] -= betweendist;
436                                         stuff_p->c[RY] -= betweendist;
437                                         stuff_p->c[RS] -= betweendist;
438                                 }
439                         }
440                 }
441
442                 if (mainll_p->str == S_STAFF &&
443                                 mainll_p->u.staff_p->staffno == s2) {
444
445                         staff_p = mainll_p->u.staff_p;
446
447                         /*
448                          * Make this staff relative to the score instead of
449                          * relative to its own center line.
450                          */
451                         staff_p->c[RN] += botoff;
452                         staff_p->c[RY] = botoff;
453                         staff_p->c[RS] += botoff;
454                 }
455         }
456 }
457 \f
458 /*
459  * Name:        posscores()
460  *
461  * Abstract:    Place which scores on which pages, and set all vertical coords.
462  *
463  * Returns:     void
464  *
465  * Description: This function decides how many scores are going to fit on each
466  *              page, based on how big they are and how much minimum space the
467  *              user wants put between them.  It calls abspage() for each page
468  *              to do final positioning and coordinate setting.
469  */
470
471 static void
472 posscores()
473
474 {
475         struct MAINLL *mainll_p;/* point along main LL */
476         struct TIMEDSSV *tssv_p;/* point along timed SSV lists */
477         struct MAINLL *page_p;  /* point at first FEED of a page */
478         struct MAINLL *ppage_p; /* point at first FEED of previous page */
479         struct MAINLL *gridpage_p; /* point at FEED for grids-at-end */
480         struct MAINLL *origpage_p; /* remember original page_p */
481         struct FEED *cfeed_p;   /* point at current scorefeed */
482         struct FEED *pfeed_p;   /* point at previous scorefeed */
483         float availheight;      /* available height on page (middle window) */
484         float remheight;        /* remaining height on page */
485         float y_start;          /* where y begins (at top of _win) */
486         float limit;            /* smallest distance allowed between scores */
487         int prevclef;           /* clef on last visible staff of prev score */
488         float clefroom;         /* room for clefs and/or measure numbers */
489         float excess;           /* extra room needed for top score */
490         float abovetopline;     /* dist from top line of score to top of score*/
491         float ink;              /* distance ink extends between inner lines */
492         float padding;          /* space between farthest extents */
493         float scoreheight;      /* height of current score */
494         float topheight, botheight;     /* height of a "top" or "bot" block */
495         int aftertitle;         /* is this the page after a title page? */
496         int firstpage;          /* are we working on the first page? */
497         int totscores;          /* number of scores on a page */
498
499         /* the following are all in inches, unlike scorepad/scoresep parms */
500         float curminpad;        /* current minscpad */
501         float curmaxpad;        /* current maxscpad */
502         float *curpad;          /* malloc: pad above each score */
503         float *maxpad;          /* malloc: maxscpad above each score */
504         float curminsep;        /* current minscsep */
505         float curmaxsep;        /* current maxscsep */
506         float *cursep;          /* malloc: sep above each score */
507         float *maxsep;          /* malloc: maxscsep above each score */
508
509         int is_block;           /* is there a block after this FEED? */
510         struct BLOCKHEAD *rememtop2_p, *remembot2_p; /* remember most current*/
511         struct BLOCKHEAD *head_p;       /* point at Header or Header2 */
512         struct BLOCKHEAD *foot_p;       /* point at Footer or Footer2 */
513
514
515         debug(16, "posscores");
516         /*
517          * In each of these arrays, array[idx] refers to distance below score
518          * number idx on a page, numbering the scores from 1 to N.  For sep, 
519          * only indices 1 through N-1 are used.  For pad, indices 0 through N
520          * are used, where 0 means above the first score and N below the last.
521          * The "sep" arrays are for distances between the outermost staff lines
522          * of neighboring scores.  The "pad" arrays are for distances between
523          * the outermost thing sticking out of those scores.  The "above"
524          * arrays are for distance currently allocated.  The "max" arrays are
525          * for the max limits we impose (when we can).
526          */
527         MALLOCA(float, cursep, MAXSCORES);
528         MALLOCA(float, curpad, MAXSCORES + 1);
529         MALLOCA(float, maxsep, MAXSCORES);
530         MALLOCA(float, maxpad, MAXSCORES + 1);
531
532         initstructs();          /* init SSVs */
533
534         /* the following need to be initialized for the coming loop */
535         curminsep = Score.minscsep * STEPSIZE;
536         curminpad = Score.minscpad * STEPSIZE;
537         curmaxsep = Score.maxscsep * STEPSIZE;
538         curmaxpad = Score.maxscpad * STEPSIZE;
539         pfeed_p = 0;
540         firstpage = YES;
541         mainll_p = Mainllhc_p;
542         rememtop2_p = remembot2_p = 0;
543
544         /* the following don't really need to be initialized; we're doing it */
545         /* just to prevent useless 'used before set' warnings */
546         page_p = 0;
547         ppage_p = 0;
548         remheight = 0;
549         y_start = 0;
550         totscores = 0;
551         prevclef = NOCLEF;
552         botheight = 0.0;
553         foot_p = 0;
554
555         /*
556          * Loop through the main linked list, looking at each feed.  Assuming
557          * the scores are packed as tightly as allowed, see how many will fit
558          * on each page.  Whenever a page fills up, call abspage() to
559          * distribute the extra white space as well as possible and set all
560          * the absolute vertical coords for that page.  At the end, call it
561          * again for the last page.
562          */
563         while (mainll_p != 0) {
564                 switch (mainll_p->str) {
565                 case S_FEED:
566                         break;  /* go handle this score */
567                 case S_SSV:
568                         /* apply, and reset vars in case some changed */
569                         asgnssv(mainll_p->u.ssv_p);
570                         curminsep = Score.minscsep * STEPSIZE;
571                         curmaxsep = Score.maxscsep * STEPSIZE;
572                         curminpad = Score.minscpad * STEPSIZE;
573                         curmaxpad = Score.maxscpad * STEPSIZE;
574                         mainll_p = mainll_p->next;
575                         continue;
576                 case S_BAR:
577                         /* apply timed SSVs; they won't affect the above
578                          * variables, but they could affect clef, which we
579                          * will need later */
580                         for (tssv_p = mainll_p->u.bar_p->timedssv_p;
581                                         tssv_p != 0; tssv_p = tssv_p->next) {
582                                 asgnssv(&tssv_p->ssv);
583                         }
584                         mainll_p = mainll_p->next;
585                         continue;
586                 default:
587                         mainll_p = mainll_p->next;
588                         continue;
589                 }
590
591                 /* if there is nothing after this FEED, break out */
592                 if (mainll_p->next == 0) {
593                         break;
594                 }
595
596                 cfeed_p = mainll_p->u.feed_p;   /* set convenient pointer */
597
598                 /*
599                  * If firstpage is set, normally there would be no pagefeed,
600                  * because the first FEED on that page is marked as a pagefeed
601                  * only if the user requested it.  If they did, that means
602                  * there was a title page with no music on it.  We need to
603                  * remember this fact, so that we know to use header2/footer2
604                  * instead of header/footer.  Only the title page would use
605                  * header/footer.
606                  */
607                 aftertitle = firstpage == YES && cfeed_p->pagefeed == YES;
608
609                 /* see if there is a block after this feed */
610                 is_block = mainll_p->next != 0 &&
611                                 mainll_p->next->str == S_BLOCKHEAD;
612
613                 scoreheight = cfeed_p->c[RN] - cfeed_p->c[RS];
614
615                 if (pfeed_p == 0) {
616                         /*
617                          * We are at the top of a page.  Point at the header
618                          * and footer that apply.  Note that if the header or
619                          * footer is unused, its height will be 0.
620                          */
621                         if (firstpage == YES && aftertitle == NO) {
622                                 head_p = &Header;
623                                 foot_p = &Footer;
624                         } else {
625                                 head_p = &Header2;
626                                 foot_p = &Footer2;
627                         }
628
629                         /* if not the first page, set pagefeed */
630                         if (firstpage == NO) {
631                                 cfeed_p->pagefeed = YES;
632                         }
633
634                         /* remember most recent settings of top2 and bot2 */
635                         if (cfeed_p->top2_p != 0) {
636                                 rememtop2_p = cfeed_p->top2_p;
637                         }
638                         if (cfeed_p->bot2_p != 0) {
639                                 remembot2_p = cfeed_p->bot2_p;
640                         }
641
642                         /*
643                          * Decide what is to be printed at the top and
644                          * bottom (inside the header(2)/footer(2) if any).
645                          * On the first page and at every pagefeed where top_p
646                          * is set, that is to be used, so leave it alone.
647                          * Otherwise use the most recent top2_p setting, so
648                          * save the value into top_p.  Later in this function,
649                          * and also in the print phase, top_p is used, not
650                          * top2_p, with exception of grids-at-end pages.
651                          */
652                         if (firstpage == NO && cfeed_p->top_p == 0) {
653                                 cfeed_p->top_p = rememtop2_p;
654                         }
655                         /* analogous for bottom */
656                         if (firstpage == NO && cfeed_p->bot_p == 0) {
657                                 cfeed_p->bot_p = remembot2_p;
658                         }
659
660                         /* set height of "top" & "bot" if they exist, else 0 */
661                         topheight = cfeed_p->top_p != 0 ?
662                                         cfeed_p->top_p->height : 0.0;
663                         botheight = cfeed_p->bot_p != 0 ?
664                                         cfeed_p->bot_p->height : 0.0;
665
666                         /*
667                          * Remove these items' size from the space available
668                          * for music, and set music's starting point.
669                          */
670                         availheight = PGHEIGHT - EFF_TOPMARGIN - EFF_BOTMARGIN
671                                 - head_p->height - foot_p->height
672                                 - topheight - botheight;
673
674                         y_start = PGHEIGHT - EFF_TOPMARGIN
675                                 - head_p->height - topheight;
676
677                         /*
678                          * If a header or top exists on this page, we need to
679                          * have pad below it.  Since we're initially packing as
680                          * tightly as possible, assume the minimum.  Reduce the
681                          * available room by that amount.  Analogous for
682                          * footer/bottom.
683                          */
684                         if (head_p->height + topheight > 0.0) {
685                                 availheight -= curminpad;
686                         }
687                         if (foot_p->height + botheight > 0.0) {
688                                 availheight -= curminpad;
689                         }
690
691                         /* increase score's RN and scoreheight if need be */
692                         if (is_block) {
693                                 /*
694                                  * Blocks have no clef or measure number, but
695                                  * clefspace() still will return a little
696                                  * something for padding, so add that in.
697                                  */
698                                 excess = clefspace(NOCLEF, 1.0, NOCLEF, 1.0,NO);
699                                 cfeed_p->c[RN] += excess;
700                                 scoreheight += excess;
701                         } else {
702                                 /*
703                                  * If clef (and measure number if that is to be
704                                  * printed) stick up higher than anything else,
705                                  * adjust the size of the score to allow for it.
706                                  */
707                                 clefroom = clefspace(NOCLEF, 1.0,
708                                         CLEF2PRINT(cfeed_p->firstvis), 1.0,
709                                         Score.measnum == YES &&firstpage == NO);
710                                 abovetopline = cfeed_p->c[RN] -
711                                         staffvertspace(cfeed_p->firstvis) / 2.0;
712                                 excess = clefroom - abovetopline;
713                                 if (excess > 0.0) {
714                                         cfeed_p->c[RN] += excess;
715                                         scoreheight += excess;
716                                 }
717                         }
718
719                         if (scoreheight > availheight) {
720                                 if (Score.units == INCHES) {
721                                         ufatal("score is too high (%.2f inches) to fit on one page (limit %.2f)",
722                                         scoreheight * Score.scale_factor,
723                                         availheight * Score.scale_factor);
724                                 } else {
725                                         ufatal("score is too high (%.2f cm) to fit on one page (limit %.2f)",
726                                         scoreheight * Score.scale_factor *
727                                         CMPERINCH, availheight *
728                                         Score.scale_factor * CMPERINCH);
729                                 }
730                         }
731
732                         /*
733                          * Set pad above the top score.  If there is a header
734                          * or top, use the values from scorepad.  If not, force
735                          * both to 0, so that none will be allowed.
736                          */
737                         if (head_p->height + topheight > 0.0) {
738                                 curpad[0] = curminpad;
739                                 maxpad[0] = curmaxpad;
740                         } else {
741                                 curpad[0] = 0.0;
742                                 maxpad[0] = 0.0;
743                         }
744
745                         remheight = availheight - scoreheight;
746                         totscores = 1;
747                         pfeed_p = cfeed_p;
748                         ppage_p = page_p;
749                         page_p = mainll_p;
750                         mainll_p = mainll_p->next;
751                         firstpage = NO;
752                         if (is_block)
753                                 prevclef = NOCLEF;
754                         else
755                                 prevclef = CLEF2PRINT(pfeed_p->lastvis);
756
757                 } else {
758
759                         /*
760                          * This will be the second or later score on this page,
761                          * if it fits, and the user did not request a manual
762                          * pagefeed.  Figure out what the minimum padding can
763                          * be between this score and the previous.  "ink" is
764                          * the distance things on the bottom visible staff of
765                          * the previous score extend from its bottom line down,
766                          * plus the distance things on the top visible staff of
767                          * the current score extend from its top line up.
768                          * curminpad is the minimum white space the user wants
769                          * to allow between scores.
770                          */
771                         if (is_block) {
772                                 ink = pfeed_p->lastdist;
773                                 clefroom = clefspace(prevclef, 1.0, NOCLEF,
774                                         1.0, NO);
775                         } else {
776                                 ink = pfeed_p->lastdist + (cfeed_p->c[RN] -
777                                         staffvertspace(cfeed_p->firstvis)/2.0);
778                                 clefroom = clefspace(prevclef, 1.0,
779                                         CLEF2PRINT(cfeed_p->firstvis), 1.0,
780                                         Score.measnum);
781                         }
782                         limit = MAX(curminsep, clefroom);
783                         if (ink < limit - curminpad) {
784                                 padding = limit - ink;
785                         } else {
786                                 padding = curminpad;
787                         }
788
789                         if (padding + scoreheight <= remheight &&
790                                                 cfeed_p->pagefeed == NO) {
791                                 /* this score fits on this page */
792                                 remheight -= padding + scoreheight;
793                                 cursep[totscores] = ink + padding;
794                                 maxsep[totscores] = curmaxsep;
795                                 curpad[totscores] = padding;
796                                 maxpad[totscores] = curmaxpad;
797                                 totscores++;
798                                 pfeed_p = cfeed_p;
799                                 mainll_p = mainll_p->next;
800                                 if (is_block)
801                                         prevclef = NOCLEF;
802                                 else
803                                         prevclef = CLEF2PRINT(pfeed_p->lastvis);
804                         } else {
805                                 /* the score does not fit */
806                                 /*
807                                  * Set pad below the bottom score.  If there is
808                                  * a footer or bottom, use the values from
809                                  * scorepad.  If not, force both to 0, so that
810                                  * none will be allowed.
811                                  */
812                                 if (foot_p->height + botheight > 0.0) {
813                                         curpad[totscores] = curminpad;
814                                         maxpad[totscores] = curmaxpad;
815                                 } else {
816                                         curpad[totscores] = 0.0;
817                                         maxpad[totscores] = 0.0;
818                                 }
819
820                                 abspage(page_p, cursep, maxsep, curpad,
821                                                 maxpad, totscores,
822                                                 remheight, y_start);
823                                 pfeed_p = 0;
824                         }
825                 }
826         }
827
828         /* in case it changes, remember the original page_p */
829         origpage_p = page_p;
830
831         /* find out what is after the last FEED */
832         if (page_p->next != 0 && (page_p->next->str == S_CLEFSIG ||
833                                   page_p->next->str == S_BLOCKHEAD)) {
834                 /*
835                  * The last top-of-page feed has music/block(s) after it.  Let
836                  * page_p continue to point at it, and for now let gridpage_p
837                  * be null.
838                  */
839                 gridpage_p = 0;
840         } else {
841                 /*
842                  * The last top-of-page feed is after all music/blocks.  Point
843                  * page_p at the previous one, and use this one for gridpage_p.
844                  */
845                 gridpage_p = page_p;
846                 page_p = ppage_p;
847         }
848
849         /*
850          * Before distributing the scores on the last page, if there are chord
851          * grids to be printed at the end, find whether they fit on this page
852          * (their height doesn't exceed remheight minus white).  If so, the
853          * subroutine places them at the bottom and returns their height.  If
854          * they don't fit, it returns zero and puts them on a separate page.
855          */
856         if (Atend_info.grids_used > 0) {
857                 float gridheight;
858
859                 /*
860                  * In case grids need to go on later page(s), we need to make
861                  * sure there is a FEED at the end of the MLL.  Its top_p and
862                  * bot_p will be used on the first grid page, and top2_p and
863                  * bot2_p will be used on later pages.
864                  */
865                 if (gridpage_p == 0) {
866                         /* find last thing in MLL that's not LINE/CURVE/PRHEAD*/
867                         for (mainll_p = Mainlltc_p;
868                                         mainll_p->str == S_LINE ||
869                                         mainll_p->str == S_CURVE ||
870                                         mainll_p->str == S_PRHEAD;
871                                         mainll_p = mainll_p->prev)
872                                 ;
873                         if (mainll_p->str == S_FEED) {
874                                 /* FEED, so reuse for gridpage FEED */
875                                 /* (it wasn't a top-of-page FEED before) */
876                                 gridpage_p = mainll_p;
877                         } else {
878                                 /* alloc new FEED to be used for grid pages */
879                                 gridpage_p = newMAINLLstruct(S_FEED, -1);
880                                 insertMAINLL(gridpage_p, Mainlltc_p);
881                         }
882
883                         /*
884                          * Both the first and later grid pages should use what
885                          * is currently remembered for top2 and bot2.
886                          */
887                         gridpage_p->u.feed_p->top_p =
888                                 gridpage_p->u.feed_p->top2_p = rememtop2_p;
889                         gridpage_p->u.feed_p->bot_p =
890                                 gridpage_p->u.feed_p->bot2_p = remembot2_p;
891                 } else {
892                         /* set pointers that are not already set */
893                         if (gridpage_p->u.feed_p->top2_p == 0) {
894                                 gridpage_p->u.feed_p->top2_p = rememtop2_p;
895                         }
896                         if (gridpage_p->u.feed_p->top_p == 0) {
897                                 gridpage_p->u.feed_p->top_p =
898                                                 gridpage_p->u.feed_p->top2_p;
899                         }
900                         if (gridpage_p->u.feed_p->bot2_p == 0) {
901                                 gridpage_p->u.feed_p->bot2_p = remembot2_p;
902                         }
903                         if (gridpage_p->u.feed_p->bot_p == 0) {
904                                 gridpage_p->u.feed_p->bot_p =
905                                                 gridpage_p->u.feed_p->bot2_p;
906                         }
907                 }
908
909                 /*
910                  * (remheight - curminpad) is how much space is available on the
911                  * last page for grids.   firstpage is needed to know whether
912                  * to use Header or Header2 (etc.) in calculations.   The next
913                  * two parms are needed for finding the correct top and bottom
914                  * sizes for the last music page, and any grid-only pages.
915                  */
916                 gridheight = grids_atend(remheight - curminpad, firstpage,
917                         page_p->u.feed_p, gridpage_p->u.feed_p);
918
919                 if (gridheight > 0.0) {
920                         /* reduce remaining height by grids and curminpad */
921                         remheight -= gridheight + curminpad;
922                 }
923         }
924
925         /*
926          * Set pad below the bottom score.  If there is a footer
927          * or bottom, use the values from scorepad.  If not, force
928          * both to 0, so that none will be allowed.
929          */
930         if (foot_p->height + botheight > 0.0) {
931                 curpad[totscores] = curminpad;
932                 maxpad[totscores] = curmaxpad;
933         } else {
934                 curpad[totscores] = 0.0;
935                 maxpad[totscores] = 0.0;
936         }
937
938         abspage(origpage_p, cursep, maxsep, curpad, maxpad, totscores,
939                         remheight, y_start);
940
941         FREE(cursep);
942         FREE(maxsep);
943         FREE(curpad);
944         FREE(maxpad);
945 }
946 \f
947 /*
948  * Name:        abspage()
949  *
950  * Abstract:    Set all absolute vertical coordinates on a page.
951  *
952  * Returns:     void
953  *
954  * Description: This function positions the scores on this page as well as
955  *              possible, and then sets all the absolute vertical coordinates
956  *              for the scores and everything in them.
957  */
958
959 static void
960 abspage(page_p, cursep, maxsep, curpad, maxpad, totscores, remheight,
961                 y_start)
962
963 struct MAINLL *page_p;  /* point at first FEED for this page */
964 float cursep[];         /* this score's top line to above score's bottom line */
965 float maxsep[];         /* the max we'd like to expand cursep to */
966 float curpad[];         /* white pad between this score and above score */
967 float maxpad[];         /* the max we'd like to expand curpad to */
968 int totscores;          /* number of scores on this page */
969 double remheight;       /* extra vertical space available, to be distributed */
970 double y_start;         /* Y coord of top of first score (before padding) */
971
972 {
973         struct MAINLL *mainll_p;/* point along main LL */
974         struct FEED *feed_p;    /* point at a score feed on this page */
975         struct CHORD *ch_p;     /* point at a chord on this page */
976         struct STAFF *staff_p;  /* point at a staff on this page */
977         float min;              /* smallest number in curpad or cursep */
978         float min2;             /* second smallest number in curpad or sep */
979         float share;            /* space to add to the min numbers each loop */
980         int mins;               /* how many numbers are tied for min */
981         int n;                  /* loop variable */
982         int *is_min;            /* pointer to array malloc'ed below */
983         int *hit_max;           /* pointer to array malloc'ed below */
984         int allmax;             /* have all scores used the max sep allowed? */
985
986
987         debug(32,"abspage file=%s line=%d totscores=%d remheight=%f y_start=%f",
988                         page_p->inputfile, page_p->inputlineno, totscores,
989                         (float)remheight, (float)y_start);
990         /*
991          * Array to hold which of the distances in curpad or cursep are
992          * minimal.
993          */
994         MALLOCA(int, is_min, MAXSCORES + 1);
995         /*
996          * Malloc an array to hold YES or NO as to whether this score's
997          * curpad or cursep has reached the maximum allowed.
998          */
999         MALLOCA(int, hit_max, MAXSCORES + 1);
1000
1001         /*
1002          * The current values in curpad[] and cursep[] are for the case of
1003          * the scores being packed as tightly as the stuff sticking out of them
1004          * and the user's specification of minscpad and minscsep allow.
1005          * maxpad[] and maxsep[] have the values of maxscpad and maxscsep
1006          * above each.  Now we need to spread the score out, distributing
1007          * remheight appropriately.
1008          */
1009         /*
1010          * First, "smooth out" curpad[], so that the numbers in it will be as
1011          * equal as possible, subject to maxpad[], but ignoring maxsep[].
1012          */
1013         while (remheight > FUDGE) {
1014                 /*
1015                  * For each score, remember in hit_max whether its curpad
1016                  * meets or exceeds the max pad allowed.  The fudge factor is
1017                  * so we'll pretend we made it, even if there is roundoff
1018                  * error.  If all scores' curpads have reached that, we're
1019                  * done, so break out.
1020                  */
1021                 allmax = YES;
1022                 for (n = 0; n <= totscores; n++) {
1023                         if (curpad[n] >= maxpad[n] - FUDGE) {
1024                                 hit_max[n] = YES;
1025                         } else {
1026                                 hit_max[n] = NO;
1027                                 allmax = NO;
1028                         }
1029                 }
1030                 if (allmax == YES) {
1031                         break;
1032                 }
1033
1034                 /*
1035                  * Find the smallest curpad among scores that haven't hit
1036                  * their max.
1037                  */
1038                 min = 1000;
1039                 for (n = 0; n <= totscores; n++) {
1040                         if (hit_max[n] == NO && curpad[n] < min)
1041                                 min = curpad[n];
1042                 }
1043
1044                 mins = 0;       /* number of curpads tied for min */
1045                 min2 = 1000;    /* second smallest curpad value */
1046
1047                 /*
1048                  * In this loop, mark which of the curpads are tied for the
1049                  * "min" value, and count how many are tied (mins).  Also, find
1050                  * the second smallest value (min2).  All this is done only for
1051                  * scores that haven't hit their max.
1052                  */
1053                 for (n = 0; n <= totscores; n++) {
1054                         if (hit_max[n] == NO) {
1055                                 if (curpad[n] == min) {
1056                                         is_min[n] = YES;
1057                                         mins++;
1058                                 } else {
1059                                         is_min[n] = NO;
1060                                         if (curpad[n] < min2) {
1061                                                 min2 = curpad[n];
1062                                         }
1063                                 }
1064                         }
1065                 }
1066
1067                 /*
1068                  * Don't let min2 exceed the maxpad of any eligible score.
1069                  * That way, when we spread the scores out to min2, we won't be
1070                  * spreading any of them beyond where they are allowed to go.
1071                  * In the next loop, ones that have reached their limit will
1072                  * get hit_max[] == YES, while other scores can continue to be
1073                  * spread more.
1074                  */
1075                 for (n = 0; n <= totscores; n++) {
1076                         if (hit_max[n] == NO && min2 > maxpad[n]) {
1077                                 min2 = maxpad[n];
1078                         }
1079                 }
1080
1081                 /*
1082                  * We're going to add to all those minimum curpads, either
1083                  * using up all of remheight, or bringing them up equal to
1084                  * min2, whichever is lower.  We add the same amount to the
1085                  * curseps, since they change by the same amount as we move
1086                  * a score.
1087                  */
1088                 share = remheight / mins;
1089                 if (share > min2 - min) {
1090                         share = min2 - min;
1091                 }
1092                 for (n = 0; n <= totscores; n++) {
1093                         if (hit_max[n] == NO && is_min[n] == YES) {
1094                                 curpad[n] += share;
1095                                 cursep[n] += share;
1096                         }
1097                 }
1098
1099                 /* decrement remheight by the amount we just used */
1100                 remheight -= mins * share;
1101         }
1102
1103         /*
1104          * "Smooth out" cursep[], so that the numbers in it will be as
1105          * equal as possible, subject to maxsep[], but ignoring maxpad[].
1106          * If there is only one score, the first "for" loop won't execute, and
1107          * we'll break out.
1108          */
1109         while (remheight > FUDGE) {
1110                 /*
1111                  * For each score, remember in hit_max whether its cursep
1112                  * meets or exceeds the max sep allowed.  The fudge factor is
1113                  * so we'll pretend we made it, even if there is roundoff
1114                  * error.  If all scores' curseps have reached that, we're
1115                  * done, so break out.
1116                  */
1117                 allmax = YES;
1118                 for (n = 1; n < totscores; n++) {
1119                         if (cursep[n] >= maxsep[n] - FUDGE) {
1120                                 hit_max[n] = YES;
1121                         } else {
1122                                 hit_max[n] = NO;
1123                                 allmax = NO;
1124                         }
1125                 }
1126                 if (allmax == YES) {
1127                         break;
1128                 }
1129
1130                 /*
1131                  * Find the smallest cursep among scores that haven't hit
1132                  * their max.
1133                  */
1134                 min = 1000;
1135                 for (n = 1; n < totscores; n++) {
1136                         if (hit_max[n] == NO && cursep[n] < min)
1137                                 min = cursep[n];
1138                 }
1139
1140                 mins = 0;       /* number of curseps tied for min */
1141                 min2 = 1000;    /* second smallest cursep value */
1142
1143                 /*
1144                  * In this loop, mark which of the curseps are tied for the
1145                  * "min" value, and count how many are tied (mins).  Also, find
1146                  * the second smallest value (min2).  All this is done only for
1147                  * scores that haven't hit their max.
1148                  */
1149                 for (n = 1; n < totscores; n++) {
1150                         if (hit_max[n] == NO) {
1151                                 if (cursep[n] == min) {
1152                                         is_min[n] = YES;
1153                                         mins++;
1154                                 } else {
1155                                         is_min[n] = NO;
1156                                         if (cursep[n] < min2) {
1157                                                 min2 = cursep[n];
1158                                         }
1159                                 }
1160                         }
1161                 }
1162
1163                 /*
1164                  * Don't let min2 exceed the maxsep of any eligible score.
1165                  * That way, when we spread the scores out to min2, we won't be
1166                  * spreading any of them beyond where they are allowed to go.
1167                  * In the next loop, ones that have reached their limit will
1168                  * get hit_max[] == YES, while other scores can continue to be
1169                  * spread more.
1170                  */
1171                 for (n = 1; n < totscores; n++) {
1172                         if (hit_max[n] == NO && min2 > maxsep[n]) {
1173                                 min2 = maxsep[n];
1174                         }
1175                 }
1176
1177                 /*
1178                  * We're going to add to all those minimum curseps, either
1179                  * using up all of remheight, or bringing them up equal to
1180                  * min2, whichever is lower.
1181                  */
1182                 share = remheight / mins;
1183                 if (share > min2 - min) {
1184                         share = min2 - min;
1185                 }
1186                 for (n = 1; n < totscores; n++) {
1187                         if (hit_max[n] == NO && is_min[n] == YES) {
1188                                 cursep[n] += share;
1189                         }
1190                 }
1191
1192                 /* decrement remheight by the amount we just used */
1193                 remheight -= mins * share;
1194         }
1195
1196         /* move to top of first score */
1197         y_start -= curpad[0];
1198
1199         feed_p = 0;     /* flag that we haven't seen the first FEED yet */
1200
1201         /*
1202          * Loop through the main linked list for this page, setting all
1203          * absolute vertical coordinates.
1204          */
1205         for (mainll_p = page_p, n = 0; mainll_p != 0 && ! (n == totscores &&
1206                         mainll_p->str == S_FEED); mainll_p = mainll_p->next) {
1207
1208                 switch (mainll_p->str) {
1209                 case S_SSV:
1210                         /* by end of page, SSVs will be up to date for there */
1211                         asgnssv(mainll_p->u.ssv_p);
1212                         break;
1213
1214                 case S_FEED:
1215                         /*
1216                          * If this is the first FEED on the page, and what
1217                          * follows is music (not a block), move to the top line
1218                          * of the first score.
1219                          */
1220                         if (feed_p == 0 && IS_CLEFSIG_FEED(mainll_p)) {
1221                                 y_start = y_start - page_p->u.feed_p->c[RN] +
1222                                  staffvertspace(page_p->u.feed_p->firstvis)/2.0;
1223                         }
1224
1225                         /*
1226                          * Set the score's absolute coordinates.  The feed_p
1227                          * pointer will be used by other cases in later loops.
1228                          */
1229                         feed_p = mainll_p->u.feed_p;
1230
1231                         /* if next is 0, this is a trailing feed, and it */
1232                         /*  really has no meaningful coords */
1233                         if (mainll_p->next == 0)
1234                                 continue;
1235
1236                         if (mainll_p->next->str == S_BLOCKHEAD) {
1237                                 /* move from top of block to middle of block */
1238                                 y_start -= feed_p->c[RN];
1239                         } else {
1240                                 /* move from top line of score to middle of
1241                                  * first staff */
1242                                 y_start -= staffvertspace(feed_p->firstvis)/2.0;
1243                         }
1244
1245                         feed_p->c[AN] = y_start + feed_p->c[RN];
1246                         feed_p->c[AY] = y_start;
1247                         feed_p->c[AS] = y_start + feed_p->c[RS];
1248
1249                         /* unless last score, set up y_start for next one */
1250                         if (n < totscores - 1) {
1251                                 /* top line of next score */
1252                                 y_start = y_start + feed_p->c[RS] +
1253                                         feed_p->lastdist - cursep[n + 1];
1254                         }
1255
1256                         n++;
1257                         break;
1258
1259                 case S_CHHEAD:
1260                         /*
1261                          * Set each chord's absolute coordinates the same as
1262                          * the feed.  These are pretty arbitrary, since they
1263                          * are using only for drawing boxes with the MUP_BB
1264                          * environment variable.
1265                          */
1266                         for (ch_p = mainll_p->u.chhead_p->ch_p; ch_p != 0;
1267                                         ch_p = ch_p->ch_p) {
1268                                 ch_p->c[AN] = feed_p->c[AN];
1269                                 ch_p->c[AY] = feed_p->c[AY];
1270                                 ch_p->c[AS] = feed_p->c[AS];
1271                         }
1272                         break;
1273
1274                 case S_BAR:
1275                         /*
1276                          * Set absolute N, Y, and S for the bar line.  Y can be
1277                          * copied from the score's Y; they are both the center
1278                          * line of the top visible staff.  But the score's N
1279                          * S can stick out, based on the groups present,
1280                          * whereas the bar line's N is the top line of the top
1281                          * staff, and its S is the bottom line of the bottom
1282                          * staff.
1283                          */
1284                         mainll_p->u.bar_p->c[AN] = feed_p->c[AY] +
1285                                 halfstaffhi(feed_p->firstvis);
1286                         mainll_p->u.bar_p->c[AY] = feed_p->c[AY];
1287                         mainll_p->u.bar_p->c[AS] = feed_p->c[AS] +
1288                                         feed_p->lastdist;
1289                         break;
1290
1291                 case S_CLEFSIG:
1292                         /*
1293                          * If the clefsig doesn't contain a pseudo bar, just
1294                          * break.  But otherwise, set this bar's coords just
1295                          * like a normal bar.
1296                          */
1297                         if (mainll_p->u.clefsig_p->bar_p == 0)
1298                                 break;
1299                         mainll_p->u.clefsig_p->bar_p->c[AN] = feed_p->c[AY] +
1300                                 halfstaffhi(feed_p->firstvis);
1301                         mainll_p->u.clefsig_p->bar_p->c[AY] = feed_p->c[AY];
1302                         mainll_p->u.clefsig_p->bar_p->c[AS] = feed_p->c[AS] +
1303                                 feed_p->lastdist - halfstaffhi(feed_p->lastvis);
1304                         break;
1305
1306                 case S_STAFF:
1307                         /* if visible, set all abs vertical coords on staff */
1308                         staff_p = mainll_p->u.staff_p;
1309                         if (staff_p->visible == YES)
1310                                 absstaff(feed_p, staff_p);
1311                         break;
1312                 }
1313
1314         }
1315
1316         FREE(is_min);
1317         FREE(hit_max);
1318 }
1319 \f
1320 /*
1321  * Name:        absstaff()
1322  *
1323  * Abstract:    Set all absolute vertical coordinates for a STAFF structure.
1324  *
1325  * Returns:     void
1326  *
1327  * Description: This function sets all the absolute vertical coords for a
1328  *              STAFF structure; those of the staff itself, and those of
1329  *              everything hanging off it.
1330  */
1331
1332 static void
1333 absstaff(feed_p, staff_p)
1334
1335 struct FEED *feed_p;            /* FEED for the score we're on */
1336 struct STAFF *staff_p;          /* the staff to be set */
1337
1338 {
1339         struct GRPSYL *gs_p;    /* point at a group of syllable */
1340         struct STUFF *stuff_p;  /* point at a STUFF structure */
1341         struct CRVLIST *pp_p;   /* point at a coord for phrase point */
1342         int v;                  /* index to voices or verses */
1343         int n;                  /* loop variable */
1344
1345
1346         debug(32, "absstaff file=%s line=%d", staff_p->groups_p[0]->inputfile,
1347                         staff_p->groups_p[0]->inputlineno);
1348         /* set the staff's own coords */
1349         staff_p->c[AN] = feed_p->c[AY] + staff_p->c[RN];
1350         staff_p->c[AY] = feed_p->c[AY] + staff_p->c[RY];
1351         staff_p->c[AS] = feed_p->c[AY] + staff_p->c[RS];
1352
1353         /* do the voice(s) */
1354         for (v = 0; v < MAXVOICES; v++) {
1355                 for (gs_p = staff_p->groups_p[v]; gs_p != 0; gs_p = gs_p->next){
1356                         gs_p->c[AY] = staff_p->c[AY] + gs_p->c[RY];
1357                         gs_p->c[AN] = staff_p->c[AY] + gs_p->c[RN];
1358                         gs_p->c[AS] = staff_p->c[AY] + gs_p->c[RS];
1359
1360                         /* if it's a group with notes, do the notes too */
1361                         if (gs_p->grpcont == GC_NOTES) {
1362                                 for (n = 0; n < gs_p->nnotes; n++) {
1363                                         gs_p->notelist[n].c[AY] = staff_p->c[AY]
1364                                                 + gs_p->notelist[n].c[RY];
1365                                         gs_p->notelist[n].c[AN] = staff_p->c[AY]
1366                                                 + gs_p->notelist[n].c[RN];
1367                                         gs_p->notelist[n].c[AS] = staff_p->c[AY]
1368                                                 + gs_p->notelist[n].c[RS];
1369                                 }
1370                         }
1371                 }
1372         }
1373
1374         /* do the verse(s) */
1375         for (v = 0; v < staff_p->nsyllists; v++) {
1376                 for (gs_p = staff_p->syls_p[v]; gs_p != 0; gs_p = gs_p->next){
1377                         gs_p->c[AY] = staff_p->c[AY] + gs_p->c[RY];
1378                         gs_p->c[AN] = staff_p->c[AY] + gs_p->c[RN];
1379                         gs_p->c[AS] = staff_p->c[AY] + gs_p->c[RS];
1380                 }
1381         }
1382
1383         /* do the stuff */
1384         for (stuff_p = staff_p->stuff_p; stuff_p != 0; stuff_p = stuff_p->next){
1385                 stuff_p->c[AY] = staff_p->c[AY] + stuff_p->c[RY];
1386                 stuff_p->c[AN] = staff_p->c[AY] + stuff_p->c[RN];
1387                 stuff_p->c[AS] = staff_p->c[AY] + stuff_p->c[RS];
1388
1389                 /* if it's a phrase/tie/slur, do the phrase points too */
1390                 if (stuff_p->stuff_type == ST_PHRASE ||
1391                     stuff_p->stuff_type == ST_TIESLUR ||
1392                     stuff_p->stuff_type == ST_TABSLUR ||
1393                     stuff_p->stuff_type == ST_BEND) {
1394                         for (pp_p = stuff_p->crvlist_p; pp_p != 0;
1395                                                 pp_p = pp_p->next)
1396                                 pp_p->y += staff_p->c[AY];
1397                 }
1398         }
1399 }
1400 \f
1401 /*
1402  * Name:        grids_atend()
1403  *
1404  * Abstract:    Determine placement of chord grids to be printed at the end.
1405  *
1406  * Returns:     height of all the grids printed on this page
1407  *
1408  * Description: This function determines the placement of chord grids that are
1409  *              to be printed at the end of the song, and sets up the data in
1410  *              Atend_info accordingly.
1411  */
1412
1413 static double
1414 grids_atend(vertavail, firstpage, mfeed_p, gfeed_p)
1415
1416 double vertavail;       /* space available for grids and spreading out scores*/
1417 int firstpage;          /* is this first page (there's only 1 page of music)?*/
1418 struct FEED *mfeed_p;   /* FEED at start of last music page */
1419 struct FEED *gfeed_p;   /* FEED applying to grid-only pages (may be same) */
1420
1421 {
1422         struct GRID *grid_p;            /* point at a grid */
1423         int ngrids;                     /* no. of grids used */
1424         float north, south, east, west; /* coords for one grid */
1425         float farnorth, farsouth, fareast, farwest; /* farthest for any grid */
1426         float hstrwid;                  /* half the width of chord string */
1427         float havail;                   /* horizonal space available */
1428         int inrow;                      /* no. of grids in one row */
1429         int nrows;                      /* no. of rows of grids */
1430         float totalheight;              /* of all the rows */
1431         float white;                    /* scorepad in inches */
1432         float upheight;                 /* height of header + top */
1433         float downheight;               /* height of bottom + footer */
1434
1435
1436         debug(32, "grids_atend vertavail=%f", (float)vertavail);
1437
1438         /* malloc array of pointers to the grids that were used */
1439         MALLOCA(struct GRID *, Atend_info.grid_p, Atend_info.grids_used);
1440
1441         /*
1442          * Set pointers to the grids that were used.  While doing this, find
1443          * the farthest extent of any grid, for each of the 4 directions.  The
1444          * size of the chord string must also be considered in this.
1445          */
1446         ngrids = 0;
1447         farnorth = farsouth = fareast = farwest = 0.0;
1448         for (grid_p = 0; (grid_p = nextgrid(grid_p)) != 0;  ) {
1449                 if (grid_p->used == NO)
1450                         continue;
1451                 Atend_info.grid_p[ngrids++] = grid_p;
1452                 gridsize(grid_p, -1, &north, &south, &east, &west);
1453                 north += strheight(grid_p->name);
1454                 hstrwid = strwidth(grid_p->name) / 2.0;
1455                 if (north > farnorth)
1456                         farnorth = north;
1457                 if (south < farsouth)
1458                         farsouth = south;
1459                 if (hstrwid > east)
1460                         east = hstrwid;
1461                 if (east > fareast)
1462                         fareast = east;
1463                 if (-hstrwid < west)
1464                         west = -hstrwid;
1465                 if (west < farwest)
1466                         farwest = west;
1467         }
1468
1469         /* sort the pointers by grid name */
1470         qsort((char *)Atend_info.grid_p, ngrids, sizeof (struct GRID *),
1471                         compgrids);
1472
1473         /* horizontal available width to use */
1474         havail = PGWIDTH - eff_leftmargin((struct MAINLL *)0)
1475                          - eff_rightmargin((struct MAINLL *)0);
1476
1477         /*
1478          * Find max we could put in one row, allowing padding.  Note that we do
1479          * not try to optimize the packing at all:  the biggest grid coord in
1480          * any direction is what we use.  The "padding" to the right of the
1481          * rightmost grid is not needed, so let it hang into the margin.
1482          */
1483         inrow = (havail + HPADGRID) / (fareast - farwest + HPADGRID);
1484         if (inrow == 0) {
1485                 ufatal("chord grid is too wide to fit on a page");
1486         }
1487
1488         /* this determines how many rows there will be; it will not change */
1489         nrows = (ngrids + inrow - 1) / inrow;
1490
1491         /*
1492          * It could be that the last row would be far from full.  So attempt to
1493          * spread the grids more equally between rows.
1494          */
1495         while (nrows > 1 && inrow > 1) {
1496                 inrow--;                /* try one less grid per row */
1497                 if ((ngrids + inrow - 1) / inrow > nrows) {
1498                         /* whoops, no. of rows increased, so undo last decr. */
1499                         inrow++;
1500                         break;
1501                 }
1502         }
1503
1504         Atend_info.grids_per_row = inrow;
1505
1506         /* spread them out appropriately */
1507         Atend_info.horz_sep = havail / (nrows == 1 ? ngrids : inrow);
1508
1509         /*
1510          * Normally, the first grid's X is as far from the left margin as the
1511          * last (on that line) grid's X is from the right margin.  But if any
1512          * grids have "N fr", fareast may be bigger than -farwest.  So move
1513          * everything to the left by half the difference.
1514          */
1515         Atend_info.firstgrid_x = eff_leftmargin((struct MAINLL *)0) +
1516                         Atend_info.horz_sep / 2.0 - (fareast + farwest) / 2.0;
1517
1518         /*
1519          * Base the vertical separation on the maximum case plus padding.  Of
1520          * course, no padding is needed below the bottom row, so subtract it.
1521          */
1522         Atend_info.vert_sep = farnorth - farsouth + VPADGRID;
1523         totalheight = nrows * Atend_info.vert_sep - VPADGRID;
1524
1525         white = Score.minscpad * STEPSIZE;
1526
1527         if (totalheight <= vertavail && gfeed_p->pagefeed == NO) {
1528                 /*
1529                  * It fits on the last page of music.  Set the absolute coord
1530                  * so that it rests above the footer and/or bottom block (if
1531                  * any) and bottom margin.
1532                  */
1533                 Atend_info.firstgrid_y = EFF_BOTMARGIN + totalheight - farnorth;
1534
1535                 downheight = (firstpage == YES ? &Footer : &Footer2)->height +
1536                         (mfeed_p->bot_p != 0 ? mfeed_p->bot_p->height : 0.0);
1537                 if (downheight > 0) {
1538                         Atend_info.firstgrid_y += downheight + white;
1539                 }
1540
1541                 Atend_info.rows_per_page = nrows;
1542
1543                 return (totalheight);
1544         }
1545
1546         /*
1547          * All grids must go on later page(s).  Find how much height must be
1548          * reserved for header/top and bottom/footer on those pages.  Since
1549          * this cannot be the first page, we always use Header2 and Footer2.
1550          */
1551         upheight = Header2.height +
1552                         (gfeed_p->top_p != 0 ? gfeed_p->top_p->height : 0.0);
1553         downheight = Footer2.height +
1554                         (gfeed_p->bot_p != 0 ? gfeed_p->bot_p->height : 0.0);
1555
1556         /* make the grid page FEED a pagefeed, in case it isn't already */
1557         gfeed_p->pagefeed = YES;
1558
1559         /*
1560          * It will have to go on other page(s).  Set the absolute coord to put
1561          * it at the top.
1562          */
1563         Atend_info.separate_page = YES;
1564         Atend_info.firstgrid_y = PGHEIGHT - EFF_TOPMARGIN -
1565                         upheight - farnorth;
1566         if (upheight > 0) {
1567                 Atend_info.firstgrid_y -= white;
1568         }
1569
1570         /* reset vertavail to the amount of space on a whole page */
1571         vertavail = PGHEIGHT - EFF_TOPMARGIN - EFF_BOTMARGIN;
1572         if (upheight > 0)
1573                 vertavail -= upheight + white;
1574         if (downheight > 0)
1575                 vertavail -= downheight + white;
1576
1577         /* find number of rows per page; must be at least 1 */
1578         Atend_info.rows_per_page = (vertavail + VPADGRID) / Atend_info.vert_sep;
1579         if (Atend_info.rows_per_page == 0)
1580                 ufatal("chords grids are too high to fit on a page");
1581
1582         /*
1583          * If there is at least 1 full page, spread the rows out evenly.  The
1584          * same spacing will be used on later pages, even though the last page
1585          * may not be full.  That's okay.
1586          */
1587         if (nrows >= Atend_info.rows_per_page) {
1588                 Atend_info.vert_sep = (vertavail + VPADGRID) /
1589                                 Atend_info.rows_per_page;
1590         }
1591
1592         return (0.0);   /* nothing goes on the last page of music */
1593 }
1594 \f
1595 /*
1596  * Name:        compgrids()
1597  *
1598  * Abstract:    Compare grid names; used by qsort.
1599  *
1600  * Returns:     negative or positive
1601  *
1602  * Description: This function returns its result based on whether the grid
1603  *              pointed to by g1_p should precede or follow g2_p.  It uses
1604  *              their names in alphabetical order, basically, but it also
1605  *              understands accidentals.  They will never be equal because the
1606  *              grids are all unique.
1607  */
1608
1609 static int
1610 compgrids(g1_p_p, g2_p_p)
1611
1612 #ifdef __STDC__
1613 const void *g1_p_p;     /* the two grid pointers to compare */
1614 const void *g2_p_p;
1615 #else
1616 char *g1_p_p;           /* the two grid pointers to compare */
1617 char *g2_p_p;
1618 #endif
1619
1620 {
1621         char *name[2];          /* pointers into first and second names */
1622         char *asc_ptr;          /* point at the first name in ASCII */
1623         char chbuff[MAXCHNAME]; /* hold the ASCII name of the first chord */
1624         int accnum[2];          /* accidental number, -2 to 2  (&& to x) */
1625         int ridx[2];            /* index to rest of string */
1626         int k;                  /* loop variable */
1627
1628
1629         /*
1630          * Translate the chords names to the way the user entered them (as
1631          * closely as possible).  Since ascii_str() overwrites the same static
1632          * area each time, we have to copy the first name to our own buffer.
1633          * Rather than wasting time using malloc(), just put it in a fixed
1634          * buffer.  If someone has an absurd name longer than MAXCHNAME, just
1635          * cut it off.
1636          */
1637         asc_ptr = ascii_str((*(struct GRID **)g1_p_p)->name, YES, NO, TM_CHORD);
1638         if ((int)strlen(asc_ptr) < MAXCHNAME) {
1639                 (void)strcpy(chbuff, asc_ptr);
1640         } else {
1641                 (void)strncpy(chbuff, asc_ptr, MAXCHNAME - 1);
1642                 chbuff[MAXCHNAME - 1] = '\0';
1643         }
1644         name[0] = chbuff;
1645         name[1] = ascii_str((*(struct GRID **)g2_p_p)->name, YES, NO, TM_CHORD);
1646
1647         /*
1648          * If chord letters differ, return based on that.  For bizarre cases
1649          * like letters not A through G, or null string, que sera sera.
1650          */
1651         if (name[0][0] != name[1][0])
1652                 return (name[0][0] - name[1][0]);
1653
1654         /*
1655          * The first chars (presumably chord letters) were the same.  They
1656          * can't be \0 because then the whole strings would be equal (null
1657          * string) but we know chord names are unique.  For each name, set a
1658          * number for its accidental, and index to what follows, if anything.
1659          */
1660         for (k = 0; k < 2; k++) {
1661                 switch (name[k][1]) {
1662                 case '&':
1663                         if (name[k][2] == '&') {
1664                                 accnum[k] = -2; /* double flat */
1665                                 ridx[k] = 3;
1666                         } else {
1667                                 accnum[k] = -1; /* flat */
1668                                 ridx[k] = 2;
1669                         }
1670                         break;
1671                 case '#':
1672                         accnum[k] = 1;          /* sharp */
1673                         ridx[k] = 2;
1674                         break;
1675                 case 'x':
1676                         accnum[k] = 2;          /* double sharp */
1677                         ridx[k] = 2;
1678                         break;
1679                 default:
1680                         accnum[k] = 0;          /* no acc is like a natural */
1681                         ridx[k] = 1;
1682                         break;
1683                 }
1684         }
1685
1686         /* if accidentals differ, that rules */
1687         if (accnum[0] != accnum[1])
1688                 return (accnum[0] - accnum[1]);
1689
1690         /* else the rest of it decides */
1691         return (strcmp(&name[0][ridx[0]], &name[1][ridx[1]]));
1692 }
1693 \f
1694 /*
1695  * Name:        proc_css()
1696  *
1697  * Abstract:    Process groups involved with cross staff stemming.
1698  *
1699  * Returns:     void
1700  *
1701  * Description: This function does all the remaining work necessary for groups
1702  *              involved in cross staff stemming.
1703  */
1704
1705 static void
1706 proc_css()
1707
1708 {
1709         struct MAINLL *mainll_p;        /* point along main LL */
1710         struct MAINLL *prevvis_p;       /* previous visible staff */
1711         struct MAINLL *nextvis_p;       /* next visible staff */
1712         struct TIMEDSSV *tssv_p;        /* point along a timed SSV list */
1713         struct STAFF *thisstaff_p;      /* point at a staff */
1714         struct GRPSYL *thisg_p;         /* point at a group */
1715         struct STUFF *stuff_p;          /* point at a stuff structure */
1716         struct CRVLIST *pp_p;           /* point at a coord for phrase point */
1717         RATIONAL vtime;                 /* start time of groups */
1718         int vidx;                       /* voice index */
1719
1720
1721         debug(16, "proc_css");
1722         initstructs();                  /* clean out old SSV info */
1723
1724         /*
1725          * Loop through the whole MLL, looking for visible staffs, and keeping
1726          * SSVs up to date (including midmeasure SSVs, since CSS notes are
1727          * affected by clef changes).
1728          */
1729         prevvis_p = 0;
1730         for (mainll_p = Mainllhc_p; mainll_p != 0; mainll_p = mainll_p->next) {
1731
1732                 switch (mainll_p->str) {
1733                 case S_STAFF:
1734                         thisstaff_p = mainll_p->u.staff_p;
1735                         /* if staff is invisible, skip it */
1736                         if (thisstaff_p->visible == NO) {
1737                                 continue;
1738                         }
1739                         break;          /* go handle this visible staff */
1740                 case S_SSV:
1741                         /* assign normal SSV */
1742                         asgnssv(mainll_p->u.ssv_p);
1743                         continue;
1744                 case S_BAR:
1745                         /* assign preceding measure's timed SSVs */
1746                         for (tssv_p = mainll_p->u.bar_p->timedssv_p;
1747                                         tssv_p != 0;
1748                                         tssv_p = tssv_p->next) {
1749                                 asgnssv(&tssv_p->ssv);
1750                         }
1751                         /* FALL THROUGH */
1752                 default:
1753                         /* set prev to null in preparation for next measure */
1754                         prevvis_p = 0;
1755                         continue;
1756                 }
1757
1758                 /* look for next visible staff, skipping invisible */
1759                 for (nextvis_p = mainll_p->next; nextvis_p != 0 &&
1760                                 nextvis_p->str == S_STAFF &&
1761                                 nextvis_p->u.staff_p->visible == NO;
1762                                 nextvis_p = nextvis_p->next) {
1763                         ;
1764                 }
1765                 /* if no more visible staffs in score, set next to null */
1766                 if (nextvis_p != 0 && nextvis_p->str != S_STAFF) {
1767                         nextvis_p = 0;
1768                 }
1769
1770                 /*
1771                  * thisstaff_p is a visible staff, and prevvis_p and nextvis_p
1772                  * are the MLL structs for the previous and next visible staffs,
1773                  * if they exist.  Loop through the voices on the this staff.
1774                  */
1775                 for (vidx = 0; vidx < MAXVOICES; vidx++) {
1776                         /*
1777                          * Loop through the groups of this voice, keeping track
1778                          * of the elapsed time, looking for groups that have
1779                          * CSS, and calling one_css() for them.
1780                          */
1781                         vtime = Zero;
1782                         for (thisg_p = thisstaff_p->groups_p[vidx]; thisg_p !=0;
1783                                         vtime = radd(vtime, thisg_p->fulltime),
1784                                         thisg_p = thisg_p->next) {
1785
1786                                 switch (thisg_p->stemto) {
1787                                 case CS_SAME:
1788                                         continue;
1789                                 case CS_ABOVE:
1790                                         if (prevvis_p == 0) {
1791                                                 l_ufatal(mainll_p->inputfile,
1792                                                 mainll_p->inputlineno,
1793                                                 "cannot cross staff stem 'with above' from top visible staff");
1794                                         }
1795                                         one_css(thisstaff_p,
1796                                                 prevvis_p->u.staff_p,
1797                                                 thisg_p, vtime);
1798                                         break;
1799                                 case CS_BELOW:
1800                                         if (nextvis_p == 0) {
1801                                                 l_ufatal(mainll_p->inputfile,
1802                                                 mainll_p->inputlineno,
1803                                                 "cannot cross staff stem 'with below' from bottom visible staff");
1804                                         }
1805                                         one_css(thisstaff_p,
1806                                                 nextvis_p->u.staff_p,
1807                                                 thisg_p, vtime);
1808                                         break;
1809                                 }
1810                         }
1811                 }
1812
1813                 prevvis_p = mainll_p;
1814         }
1815
1816         /*
1817          * Now we have to call beamstem() again, to do the work that it
1818          * couldn't do before on groups affected by CSS.
1819          */
1820         CSSpass = YES;
1821         beamstem();
1822
1823         /*
1824          * Do "horizontal avoidance": moving CSS groups sideways if necessary
1825          * because they would collide with groups on the other staff.
1826          */
1827         horzavoid();
1828
1829         /*
1830          * Back in relvert.c, we skipped placing tie/slur/bend/phrases whose
1831          * endpoint groups were affected by CSS.  Now that we know where the
1832          * final group boundaries are, we set up the coords for these items.
1833          * tieslur_points and phrase_points destroy groups' AN and AS, and
1834          * depends on them starting out as zero.  So zero them now and restore
1835          * them later.  Because these items can cross bar lines, we need
1836          * to zap all of these coords in this first loop, and have a separate
1837          * loop to do the main work (and restore the groups' coords).
1838          */
1839         for (mainll_p = Mainllhc_p; mainll_p != 0; mainll_p = mainll_p->next) {
1840                 if (mainll_p->str != S_STAFF) {
1841                         continue;
1842                 }
1843                 thisstaff_p = mainll_p->u.staff_p;
1844
1845                 for (vidx = 0; vidx < MAXVOICES; vidx++) {
1846                         for (thisg_p = thisstaff_p->groups_p[vidx];
1847                                         thisg_p != 0; thisg_p = thisg_p->next) {
1848                                 thisg_p->c[AN] = 0.0;
1849                                 thisg_p->c[AS] = 0.0;
1850                         }
1851                 }
1852         }
1853
1854         for (mainll_p = Mainllhc_p; mainll_p != 0; mainll_p = mainll_p->next) {
1855                 if (mainll_p->str != S_STAFF) {
1856                         continue;
1857                 }
1858                 thisstaff_p = mainll_p->u.staff_p;
1859
1860                 /*
1861                  * Find and handle every tie/slur/bend/phrase starting in this
1862                  * staff.
1863                  */
1864                 for (stuff_p = thisstaff_p->stuff_p;
1865                                 stuff_p != 0; stuff_p = stuff_p->next) {
1866                         switch (stuff_p->stuff_type) {
1867                         case ST_PHRASE:
1868                                 if (css_affects_phrase(stuff_p,
1869                                                         mainll_p) == YES) {
1870                                         phrase_points(mainll_p, stuff_p);
1871
1872                                         stuff_p->c[AY] = thisstaff_p->c[AY]
1873                                                        + stuff_p->c[RY];
1874                                         stuff_p->c[AN] = thisstaff_p->c[AY]
1875                                                        + stuff_p->c[RN];
1876                                         stuff_p->c[AS] = thisstaff_p->c[AY]
1877                                                        + stuff_p->c[RS];
1878
1879                                         /* do the phrase points too */
1880                                         for (pp_p = stuff_p->crvlist_p;
1881                                              pp_p != 0; pp_p = pp_p->next) {
1882
1883                                                 pp_p->y += thisstaff_p->c[AY];
1884                                         }
1885                                 }
1886                                 break;
1887                         case ST_TIESLUR:
1888                         case ST_BEND:
1889                                 if (css_affects_tieslurbend(stuff_p,
1890                                                         mainll_p) == YES) {
1891                                         if (stuff_p->stuff_type == ST_TIESLUR) {
1892                                                 tieslur_points(mainll_p, stuff_p);
1893                                         } else {
1894                                                 bend_points(mainll_p, stuff_p);
1895                                         }
1896
1897                                         stuff_p->c[AY] = thisstaff_p->c[AY]
1898                                                        + stuff_p->c[RY];
1899                                         stuff_p->c[AN] = thisstaff_p->c[AY]
1900                                                        + stuff_p->c[RN];
1901                                         stuff_p->c[AS] = thisstaff_p->c[AY]
1902                                                        + stuff_p->c[RS];
1903
1904                                         /* do the tie/slur/bend points too */
1905                                         for (pp_p = stuff_p->crvlist_p;
1906                                              pp_p != 0; pp_p = pp_p->next) {
1907
1908                                                 pp_p->y += thisstaff_p->c[AY];
1909                                         }
1910                                 }
1911                                 break;
1912                         }
1913                 }
1914
1915                 /*
1916                  * phrase_points destroys groups' AN and AS.  And some code in
1917                  * the second pass of beamstem.c doesn't set the absolute
1918                  * coords of groups.  So go through now and set the absolute
1919                  * coords of all groups.
1920                  */
1921                 for (vidx = 0; vidx < MAXVOICES; vidx++) {
1922                         for (thisg_p = thisstaff_p->groups_p[vidx];
1923                                         thisg_p != 0; thisg_p = thisg_p->next) {
1924                                 thisg_p->c[AN] = thisstaff_p->c[AY]
1925                                                 + thisg_p->c[RN];
1926                                 thisg_p->c[AY] = thisstaff_p->c[AY]
1927                                                 + thisg_p->c[RY];
1928                                 thisg_p->c[AS] = thisstaff_p->c[AY]
1929                                                 + thisg_p->c[RS];
1930                         }
1931                 }
1932         }
1933 }
1934 \f
1935 /*
1936  * Name:        one_css()
1937  *
1938  * Abstract:    Process one group involved with cross staff stemming.
1939  *
1940  * Returns:     void
1941  *
1942  * Description: This function processes one CSS group.  It moves the CSS notes
1943  *              in the group to fall into the correct place on the other staff.
1944  *              When necessary, it also adjusts the group boundary.
1945  */
1946
1947 static void
1948 one_css(ts_p, os_p, tg_p, time)
1949
1950 struct STAFF *ts_p;             /* This Staff, the normal one for the grpsyl */
1951 struct STAFF *os_p;             /* Other Staff that the grpsyl has notes on */
1952 struct GRPSYL *tg_p;            /* This Grpsyl */
1953 RATIONAL time;                  /* time offset of this grpsyl */
1954
1955 {
1956         struct GRPSYL *og_p;    /* Other Grpsyl (some grpsyl on other staff) */
1957         int foundclef;          /* found a clef change on other staff? */
1958         RATIONAL cleftime;      /* time at which the last clef change happens*/
1959         RATIONAL tt;            /* temporary time variable */
1960         float offset;           /* distance from old note position to new */
1961         int upfromc4;           /* steps up from middle C */
1962         int clef;               /* clef in force on other staff */
1963         int vidx;               /* voice index */
1964         int n;                  /* loop variable */
1965
1966
1967         /*
1968          * Set globals like Staffscale according our staff.  The parse phase
1969          * ensures that the two staffs have the same staffscale.
1970          */
1971         set_staffscale(ts_p->staffno);
1972
1973         /*
1974          * We need to find out what clef is in force on the other staff.  We
1975          * start with the current value; but it may change midmeasure.  We
1976          * can't just use the timed SSVs, because there are weird cases
1977          * where the clef got put farther to the right (because the clef was
1978          * changed before rests or spaces).  So we have to search all the
1979          * voices for clefs.  We look for the rightmost clef that does not
1980          * exceed the given time value.
1981          */
1982         /* find clef in force on other staff at start of this measure */
1983         clef = svpath(os_p->staffno, CLEF)->clef;
1984         foundclef = NO;
1985         cleftime = Zero;
1986         for (vidx = 0; vidx < MAXVOICES; vidx++) {
1987                 tt = Zero;
1988                 for (og_p = os_p->groups_p[vidx]; og_p != 0 && LE(tt, time);
1989                                 og_p = og_p->next) {
1990                         /* if group has a clef, and either it's the first group
1991                          * found to have one or it's later than the latest such
1992                          * group found so far . . . */
1993                         if (og_p->clef != NOCLEF &&
1994                                         (foundclef == NO || GT(tt, cleftime))) {
1995                                 foundclef = YES;
1996                                 clef = og_p->clef;      /* remember this clef*/
1997                                 cleftime = tt;          /* and when it was */
1998                         }
1999                         tt = radd(tt, og_p->fulltime);
2000                 }
2001         }
2002
2003         /*
2004          * Everything that has to move will move by the same offset.  Calculate
2005          * it, using the first CSS note.  First find its stepsup on the new
2006          * staff, like setnotes.c does for the normal staff.  Subtract new
2007          * minus old vertical positions.
2008          */
2009         n = FCNI(tg_p);
2010         upfromc4 = (tg_p->notelist[n].octave - 4) * 7 +
2011                 Letshift[ tg_p->notelist[n].letter - 'a' ];
2012         tg_p->notelist[n].stepsup = upfromc4 + clef - ALTO;
2013         offset = (os_p->c[AY] + tg_p->notelist[n].stepsup * Stepsize) -
2014                 tg_p->notelist[n].c[AY];
2015
2016         /* move all the CSS notes and their dots */
2017         for ( ; n <= LCNI(tg_p); n++) {
2018                 upfromc4 = (tg_p->notelist[n].octave - 4) * 7 +
2019                         Letshift[ tg_p->notelist[n].letter - 'a' ];
2020                 tg_p->notelist[n].stepsup = upfromc4 + clef - ALTO;
2021                 tg_p->notelist[n].c[RN] += offset;
2022                 tg_p->notelist[n].c[RY] += offset;
2023                 tg_p->notelist[n].c[RS] += offset;
2024                 tg_p->notelist[n].c[AN] += offset;
2025                 tg_p->notelist[n].c[AY] += offset;
2026                 tg_p->notelist[n].c[AS] += offset;
2027                 if (tg_p->dots > 0) {
2028                         tg_p->notelist[n].ydotr += offset;
2029                 }
2030         }
2031
2032         /*
2033          * If the CSS note(s) were not on the stemside, stemlen and group
2034          * boundaries were set already in beamstem.c, but we need to fix them
2035          * here to account for moving the CSS notes.
2036          */
2037         if (STEMSIDE_CSS(tg_p) == NO) {
2038                 if (tg_p->stemlen != 0.0) {
2039                         tg_p->stemlen += fabs(offset);
2040                 }
2041                 if (tg_p->stemdir == UP) {
2042                         tg_p->c[RS] = tg_p->notelist[tg_p->nnotes - 1].c[RS]
2043                                         - Stdpad;
2044                         tg_p->c[AS] = tg_p->notelist[tg_p->nnotes - 1].c[AS]
2045                                         - Stdpad;
2046                 } else {
2047                         tg_p->c[RN] = tg_p->notelist[0].c[RN] + Stdpad;
2048                         tg_p->c[AN] = tg_p->notelist[0].c[AN] + Stdpad;
2049                 }
2050         }
2051 }
2052 \f
2053 /*
2054  * Name:        horzavoid()
2055  *
2056  * Abstract:    Move CSS groups horizontally to avoid collisions on other staff.
2057  *
2058  * Returns:     void
2059  *
2060  * Description: This function goes through the MLL, and for each CSS group,
2061  *              calls a function to do horizontal avoidance.
2062  */
2063
2064 static void
2065 horzavoid()
2066
2067 {
2068         struct MAINLL *mainll_p;        /* point along main LL */
2069         struct GRPSYL *gs_p;            /* point at a group */
2070         int vidx;                       /* voice index */
2071         RATIONAL time;                  /* start time of a group */
2072
2073
2074         for (mainll_p = Mainllhc_p; mainll_p != 0; mainll_p = mainll_p->next) {
2075                 if (mainll_p->str != S_STAFF) {
2076                         continue;
2077                 }
2078
2079                 for (vidx = 0; vidx < MAXVOICES; vidx++) {
2080                         time = Zero;
2081                         for (gs_p = mainll_p->u.staff_p->groups_p[vidx];
2082                                         gs_p != 0; gs_p = gs_p->next) {
2083                                 if (gs_p->stemto != CS_SAME) {
2084                                         avoidone(mainll_p, gs_p, time);
2085                                 }
2086                                 time = radd(time, gs_p->fulltime);
2087                         }
2088                 }
2089         }
2090 }
2091 \f
2092 /*
2093  * Name:        avoidone()
2094  *
2095  * Abstract:    Move CSS group horizontally to avoid collisions on other staff.
2096  *
2097  * Returns:     void
2098  *
2099  * Description: This function finds whether the given group collides with any
2100  *              groups on the other staff.  If so, it moves that group, along
2101  *              with all other groups on its staff and their preceding grace
2102  *              groups, to the right enough so that the group no longer
2103  *              collides.  But it won't move it so far that it would collide
2104  *              with a later group on its own staff.
2105  */
2106
2107 static void
2108 avoidone(mainll_p, cssg_p, time)
2109
2110 struct MAINLL *mainll_p;        /* the MLL for our group's staff */
2111 struct GRPSYL *cssg_p;          /* the CSS group we are working on */
2112 RATIONAL time;                  /* time offset of this group */
2113
2114 {
2115         struct MAINLL *mll_p;   /* point along main LL */
2116         int otherstaffno;       /* staff where the CSS notes are */
2117         struct GRPSYL *gs_p;    /* point along grpsyl lists */
2118         struct GRPSYL *gs2_p;   /* another pointer along grpsyl lists */
2119         struct CHORD *ch_p;     /* point at chord we're in */
2120         float movedist;         /* distance to move groups */
2121         float otherhorz;        /* east boundary of groups on other staff */
2122         float slope;            /* slope of a beam */
2123         float deltax;           /* change in X coord of stem tip */
2124         int gotone;             /* flag variable */
2125         int n;                  /* loop variable */
2126
2127
2128         /* never move the group if the user is forcing it with "ho" */
2129         if (cssg_p->ho_usage != HO_NONE) {
2130                 return;
2131         }
2132
2133         /*
2134          * Find the other staff's number.
2135          */
2136         if (cssg_p->stemto == CS_ABOVE) {
2137                 for (mll_p = mainll_p->prev; mll_p != 0 && mll_p->str == S_STAFF
2138                 && mll_p->u.staff_p->visible == NO; mll_p = mll_p->prev) {
2139                         ;
2140                 }
2141         } else {
2142                 for (mll_p = mainll_p->next; mll_p != 0 && mll_p->str == S_STAFF
2143                 && mll_p->u.staff_p->visible == NO; mll_p = mll_p->next) {
2144                         ;
2145                 }
2146         }
2147         if (mll_p == 0 || mll_p->str != S_STAFF) {
2148                 pfatal("missing staff in avoidone");
2149         }
2150         otherstaffno = mll_p->u.staff_p->staffno;
2151
2152         /*
2153          * Find what groups, if any, the other staff has at this time value.
2154          * First we find the GPRSYL at which the search begins.
2155          */
2156         if (cssg_p->stemto == CS_ABOVE) {
2157                 /*
2158                  * We will start the search at this first grpsyl in the chord.
2159                  */
2160                 ch_p = gs2ch(mainll_p, cssg_p);
2161                 gs_p = ch_p->gs_p;
2162         } else {
2163                 /*
2164                  * We will start the search at our group, or if it is grace,
2165                  * the main group that follows.
2166                  */
2167                 for (gs_p = cssg_p; gs_p->grpvalue == GV_ZERO;
2168                                 gs_p = gs_p->next) {
2169                         ;
2170                 }
2171                 ch_p = 0;       /* remember we don't know the chord */
2172         }
2173
2174         /* find the first GRPSYL, if any, on the other staff at this time */
2175         for ( ; gs_p != 0 && gs_p->staffno < otherstaffno; gs_p = gs_p->gs_p) {
2176                 ;
2177         }
2178
2179         /* if no groups on the other staff, there is no need to move anything */
2180         if (gs_p == 0 || gs_p->grpsyl == GS_SYLLABLE ||
2181                         gs_p->staffno > otherstaffno) {
2182                 return;
2183         }
2184
2185         /*
2186          * Find the easternmost extent of any group on the other staff that
2187          * extends far enough vertically to run into our group.  We don't care
2188          * about grace groups, because they are on the west side, and we are
2189          * going to move our group to the east side.
2190          */
2191         gotone = NO;
2192         otherhorz = 0.0;        /* avoid "used before set" warning */
2193         for ( ; gs_p != 0 && gs_p->grpsyl == GS_GROUP &&
2194                         gs_p->staffno == otherstaffno; gs_p = gs_p->gs_p) {
2195                 /* spaces never interfere; mr and mrpt rarely do, and their
2196                  * coords make them seem really wide, so ignore them too */
2197                 if (gs_p->grpcont == GC_SPACE || gs_p->is_meas == YES) {
2198                         continue;
2199                 }
2200                 if (cssg_p->stemto == CS_ABOVE && cssg_p->c[AN] <= gs_p->c[AS]){
2201                         continue;
2202                 }
2203                 if (cssg_p->stemto == CS_BELOW && cssg_p->c[AS] >= gs_p->c[AN]){
2204                         continue;
2205                 }
2206                 if (gotone == NO || gs_p->c[AE] > otherhorz) {
2207                         otherhorz = gs_p->c[AE];
2208                         gotone = YES;
2209                 }
2210         }
2211
2212         /*
2213          * If our group doesn't reach the other staff's groups vertically,
2214          * there is no need to move anything.
2215          */
2216         if (gotone == NO) {
2217                 return;
2218         }
2219
2220         /*
2221          * Find how far we'd need to move our group to the right to be beyond
2222          * any of the other staff's groups.  If somehow that is not positive,
2223          * there is no need to move.
2224          */
2225         movedist = otherhorz - cssg_p->c[AW];
2226         if (movedist <= 0.0) {
2227                 return;
2228         }
2229
2230         /* find the first nongrace group at this time on our staff */
2231         if (cssg_p->vno == 1) {
2232                 for (gs_p = cssg_p; gs_p->grpvalue == GV_ZERO;
2233                                 gs_p = gs_p->next) {
2234                         ;
2235                 }
2236         } else {
2237                 if (ch_p == 0) {
2238                         ch_p = gs2ch(mainll_p, cssg_p);
2239                 }
2240                 /* find the first GRPSYL, if any, on our staff at this time */
2241                 for (gs_p = ch_p->gs_p; gs_p != 0 && gs_p->staffno <
2242                                 cssg_p->staffno; gs_p = gs_p->gs_p) {
2243                         ;
2244                 }
2245         }
2246
2247         /*
2248          * For each group on this staff in this chord, and for all their
2249          * preceding grace groups, move them to the east.  Adjust stem lengths
2250          * of beamed groups.
2251          */
2252         for ( ; gs_p != 0 && gs_p->grpsyl == GS_GROUP &&
2253                         gs_p->staffno == cssg_p->staffno; gs_p = gs_p->gs_p) {
2254
2255                 /* never move the group if the user is forcing it with "ho" */
2256                 if (gs_p->ho_usage != HO_NONE) {
2257                         continue;
2258                 }
2259
2260                 /*
2261                  * If the group is beamed and the beam is not horizontal, the
2262                  * stem length needs to be changed so it will meet the beam.
2263                  */
2264                 if (gs_p->beamloc != NOITEM && gs_p->grpcont == GC_NOTES) {
2265                         /*
2266                          * Find a neighboring group in the beamed set so we can
2267                          * find the beam's slope.  The prev group is already
2268                          * corrected; our group and the next group haven't been
2269                          * moved yet; so the stems of all 3 are currently
2270                          * touching the beam and are valid for finding slope.
2271                          */
2272                         if (gs_p->beamloc == STARTITEM) {
2273                                 gs2_p = nextsimilar(gs_p);
2274                         } else {
2275                                 gs2_p = prevsimilar(gs_p);
2276                         }
2277                         slope = (find_y_stem(gs2_p) - find_y_stem(gs_p)) /
2278                                 (find_x_stem(gs2_p) - find_x_stem(gs_p));
2279
2280                         deltax = slope * movedist;
2281
2282                         if (gs_p->stemdir == UP) {
2283                                 gs_p->stemlen += deltax;
2284                                 gs_p->c[RN] += deltax;
2285                                 gs_p->c[AN] += deltax;
2286                         } else {
2287                                 gs_p->stemlen -= deltax;
2288                                 gs_p->c[RS] += deltax;
2289                                 gs_p->c[AS] += deltax;
2290                         }
2291                 }
2292
2293                 /*
2294                  * Always do our group (a nongrace group), then loop
2295                  * additionally for all preceding graces.
2296                  */
2297                 gs2_p = gs_p;
2298                 do {
2299                         gs2_p->c[AW] += movedist;
2300                         gs2_p->c[AX] += movedist;
2301                         gs2_p->c[AE] += movedist;
2302
2303                         /* if it's a group with notes, do the notes too */
2304                         if (gs2_p->grpcont == GC_NOTES) {
2305                                 for (n = 0; n < gs2_p->nnotes; n++) {
2306                                         gs2_p->notelist[n].c[AW] += movedist;
2307                                         gs2_p->notelist[n].c[AX] += movedist;
2308                                         gs2_p->notelist[n].c[AE] += movedist;
2309                                 }
2310                         }
2311
2312                         gs2_p = gs2_p->prev;
2313                 } while (gs2_p != 0 && gs2_p->grpvalue == GV_ZERO);
2314         }
2315 }
2316 \f
2317 /*
2318  * Name:        set_csb_stems()
2319  *
2320  * Abstract:    Set stem lengths for groups involved in cross staff beaming.
2321  *
2322  * Returns:     void
2323  *
2324  * Description: This function searches the MLL for cross staff beaming places.
2325  *              For each one, it calls onecsb() to set the stem lengths.
2326  */
2327
2328 static void
2329 set_csb_stems()
2330
2331 {
2332         struct MAINLL *mainll_p;        /* point along main LL */
2333         struct MAINLL *mll_p;           /* point along main LL again */
2334         struct STAFF *staff1_p, *staff2_p; /* point at top and bottom staffs */
2335         struct GRPSYL *gs1_p, *gs2_p;   /* point at top and bottom groups */
2336         int v, bv;                      /* loop thru voices, top and bottom */
2337         RATIONAL vtime1, vtime2;        /* start time of groups */
2338
2339
2340         debug(16, "set_csb_stems");
2341         initstructs();                  /* clean out old SSV info */
2342
2343         /*
2344          * Loop through the whole MLL, looking for visible staffs that are
2345          * not the last visible staff in their score.  Then find cross staff
2346          * beamings and call a function to set stem lengths.
2347          */
2348         for (mainll_p = Mainllhc_p; mainll_p != 0; mainll_p = mainll_p->next) {
2349                 /* apply SSVs to keep staffscale up to date */
2350                 if (mainll_p->str == S_SSV) {
2351                         asgnssv(mainll_p->u.ssv_p);
2352                         continue;
2353                 }
2354
2355                 if (mainll_p->str != S_STAFF)
2356                         continue;
2357
2358                 /* if staff is invisible, skip it */
2359                 staff1_p = mainll_p->u.staff_p;
2360                 if (staff1_p->visible == NO)
2361                         continue;
2362
2363                 /* look for next visible staff, skipping invisible */
2364                 for (mll_p = mainll_p->next; mll_p != 0 && mll_p->str ==
2365                                 S_STAFF && mll_p->u.staff_p->visible == NO;
2366                                 mll_p = mll_p->next)
2367                         ;
2368                 /* if no more visible staffs in score, skip */
2369                 if (mll_p == 0 || mll_p->str != S_STAFF)
2370                         continue;
2371
2372                 staff2_p = mll_p->u.staff_p;
2373
2374                 /*
2375                  * staff1_p and staff2_p are two neighboring visible staffs
2376                  * (possibly with invisible ones in between).  Loop through the
2377                  * voices on the top staff.  For ones that don't exist, their
2378                  * pointers will be 0 and the inside loop will do nothing.
2379                  */
2380                 for (v = 0; v < MAXVOICES; v++) {
2381                         /*
2382                          * Loop through the groups of this voice, keeping track
2383                          * of the elapsed time, looking for the first group of
2384                          * each CSB set that is joined with the staff below.
2385                          * It could be any of the voices on the staff below.
2386                          * The parser deals with any checks concerning voices
2387                          * being in the way of each other.
2388                          */
2389                         vtime1 = Zero;
2390                         for (gs1_p = staff1_p->groups_p[v]; gs1_p != 0;
2391                                         vtime1 = radd(vtime1, gs1_p->fulltime),
2392                                         gs1_p = gs1_p->next) {
2393
2394                                 if (gs1_p->beamto != CS_BELOW ||
2395                                     gs1_p->beamloc != STARTITEM)
2396                                         continue;
2397
2398                                 for (bv = 0; bv < MAXVOICES; bv++) {
2399                                         vtime2 = Zero;
2400                                         for (gs2_p = staff2_p->groups_p[bv];
2401                                                         gs2_p != 0 &&
2402                                                         (LT(vtime2, vtime1) ||
2403                                                         gs2_p->grpvalue ==
2404                                                                 GV_ZERO);
2405                                                         gs2_p = gs2_p->next) {
2406                                                 vtime2 = radd(vtime2,
2407                                                         gs2_p->fulltime);
2408                                         }
2409                                         if (gs2_p != 0 && EQ(vtime2, vtime1) &&
2410                                             gs2_p->beamto == CS_ABOVE &&
2411                                             gs2_p->beamloc == STARTITEM) {
2412
2413                                                 onecsb(gs1_p, gs2_p);
2414                                         }
2415                                 }
2416                         }
2417                 }
2418         }
2419 }
2420 \f
2421 /*
2422  * Name:        onecsb()
2423  *
2424  * Abstract:    Set stem lengths for one instance of cross staff beaming.
2425  *
2426  * Returns:     void
2427  *
2428  * Description: This function finds the stem directions on the two staffs of
2429  *              a CSB and the first and last groups of it that are note groups.
2430  *              If the user didn't specify the stem lengths for those outer
2431  *              groups (which determines the equation of the beams), it calls a
2432  *              function to decide what the equation should be; otherwise it
2433  *              finds the equation in-line.  Then it sets all the groups' stem
2434  *              lengths.
2435  */
2436
2437 /*
2438  * Given the STARTITEM group of a CSB (whether notes or space), return the
2439  * first CSB group that is notes.  Embedded grace groups are not part of CSB.
2440  */
2441 #define FIRSTCSB(gs_p)  (gs_p->grpcont == GC_NOTES ? gs_p : nextcsb(gs_p))
2442
2443 static void
2444 onecsb(start1_p, start2_p)
2445
2446 struct GRPSYL *start1_p;        /* first GRPSYL on top staff */
2447 struct GRPSYL *start2_p;        /* first GRPSYL on bottom staff */
2448
2449 {
2450         struct GRPSYL *gs_p;    /* point at a group */
2451         int topdir, botdir;     /* stem directions of the two lists */
2452         struct GRPSYL *end1_p, *end2_p; /* ending group in each list */
2453         struct GRPSYL *first_p, *last_p;/* first and last note groups in CSB */
2454         float firstx, lastx;    /* x coords of end of stems */
2455         float firsty, lasty;    /* y coords of stems */
2456         float b0, b1;           /* y intercept and slope of the beam */
2457         float stemshift;        /* x distance of stem from center of note */
2458         float x;                /* x coord of a stem */
2459         float outstem;  /* the part of the stemlen outside notes of group */
2460         float hi;               /* height of a "with" list item */
2461         int n;                  /* loop variable */
2462
2463
2464         /*
2465          * Set globals like Staffscale for use by the rest of the file.  The
2466          * parse phase ensures that the two staffs have the same staffscale.
2467          */
2468         set_staffscale(start1_p->staffno);
2469
2470         topdir = botdir = UP;   /* prevent useless 'used before set' warnings */
2471
2472         /*
2473          * Find stemdir of the top groups.  (They will be consistent; that was
2474          * enforced in dobunch().)  Set end1_p to the last group.
2475          */
2476         for (gs_p = FIRSTCSB(start1_p); gs_p != 0; gs_p = nextcsb(gs_p)) {
2477                 if (gs_p->grpcont == GC_NOTES)
2478                         topdir = gs_p->stemdir;
2479         }
2480         for (end1_p = start1_p; end1_p != 0 && end1_p->beamloc != ENDITEM;
2481                         end1_p = nextnongrace(end1_p))
2482                 ;
2483         if (end1_p == 0)
2484                 pfatal("no ENDITEM in beamed set (onecsb[1])");
2485
2486         /* do the same for the bottom groups */
2487         for (gs_p = FIRSTCSB(start2_p); gs_p != 0; gs_p = nextcsb(gs_p)) {
2488                 if (gs_p->grpcont == GC_NOTES)
2489                         botdir = gs_p->stemdir;
2490         }
2491         for (end2_p = start2_p; end2_p != 0 && end2_p->beamloc != ENDITEM;
2492                         end2_p = nextnongrace(end2_p))
2493                 ;
2494         if (end2_p == 0)
2495                 pfatal("no ENDITEM in beamed set (onecsb[2])");
2496
2497         if (topdir == UP && botdir == DOWN) {
2498                 l_ufatal(start2_p->inputfile, start2_p->inputlineno,
2499                 "when beaming across staffs, cannot have stems up on top staff and down on bottom");
2500         }
2501
2502         /*
2503          * Set first_p and last_p to the first and last note groups, whichever
2504          * staff(s) they are on.
2505          */
2506         first_p = start1_p->grpcont == GC_NOTES ? start1_p : start2_p;
2507         last_p = end1_p->grpcont == GC_NOTES ? end1_p : end2_p;
2508
2509         /*
2510          * Find half the width of a note head; the stems will need to be
2511          * shifted by that amount from the center of the notes so that they
2512          * will meet the edge of the notes properly.
2513          */
2514         stemshift = getstemshift(first_p);
2515
2516
2517         /*
2518          * The user must either specify a stem length for both first and last
2519          * groups, or neither.  (The parse phase enforces that.)  If neither,
2520          * call a function to determine a line for a beam.  It sets b0 and b1
2521          * for that line.
2522          */
2523         if (IS_STEMLEN_UNKNOWN(first_p->stemlen) ||
2524             IS_STEMLEN_UNKNOWN(last_p->stemlen)) {
2525                 /*
2526                  * User did not provide both outer stem lengths.  Find the best
2527                  * line.  But if the stemlen parm was zero, we get back "NO",
2528                  * and we set all stems to zero.
2529                  */
2530                 if (calcline(start1_p, end1_p, start2_p, end2_p, first_p,
2531                                 last_p, topdir, botdir, &b0, &b1) == NO) {
2532                         for (gs_p = first_p; gs_p != end1_p->next;
2533                              gs_p = nxtbmnote(gs_p, start1_p, end1_p->next)) {
2534                                 gs_p->stemlen = 0.0;
2535                         }
2536                         return;
2537                 }
2538         } else {
2539                 /*
2540                  * User provided outer stem lengths.  If they are zero, force
2541                  * all groups to zero and get out.  There will be no stems and
2542                  * no beams.
2543                  */
2544                 if (first_p->stemlen == 0.0 && last_p->stemlen == 0.0) {
2545                         for (gs_p = first_p; gs_p != end1_p->next;
2546                              gs_p = nxtbmnote(gs_p, start1_p, end1_p->next)) {
2547                                 gs_p->stemlen = 0.0;
2548                         }
2549                         return;
2550                 }
2551
2552                 /*
2553                  * User provided outer stem lengths; calculate b0 and b1.
2554                  * First get Y coords of endpoints of first and last stems.
2555                  */
2556                 first_p->stemlen *= Staffscale;
2557                 last_p->stemlen *= Staffscale;
2558                 firsty = first_p->stemdir == UP ?
2559                         first_p->notelist[0].c[AY] + first_p->stemlen :
2560                         first_p->notelist[ first_p->nnotes - 1 ].c[AY]
2561                                 - first_p->stemlen;
2562                 lasty = last_p->stemdir == UP ?
2563                         last_p->notelist[0].c[AY] + last_p->stemlen :
2564                         last_p->notelist[ last_p->nnotes - 1 ].c[AY]
2565                                 - last_p->stemlen;
2566                 /*
2567                  * If first and last are opposite, adjust the right end of
2568                  * the line.
2569                  */
2570                 if (first_p->stemdir != last_p->stemdir)
2571                         lasty += end_bm_offset(start1_p, last_p, 8);
2572
2573                 /* get X coords; calculate b0 and b1 */
2574                 firstx = first_p->c[AX] + stemshift *
2575                                 (first_p->stemdir == DOWN ? -1 : 1);
2576                 lastx = last_p->c[AX] + stemshift *
2577                                 (last_p->stemdir == DOWN ? -1 : 1);
2578                 b1 = (lasty - firsty) / (lastx - firstx); /* slope */
2579                 b0 = firsty - b1 * firstx;                /* y intercept */
2580         }
2581
2582
2583         /*
2584          * At this point we know the equation for the beams.  Figure out and
2585          * set the correct stem lengths for all of these beamed groups.
2586          */
2587         if (topdir == botdir) {         /* all stems have the same direction */
2588                 if (first_p->stemdir == DOWN)
2589                         stemshift = -stemshift;
2590
2591                 /* loop through the top staff's groups */
2592                 for (gs_p = FIRSTCSB(start1_p); gs_p != 0; gs_p=nextcsb(gs_p)){
2593                         x = gs_p->c[AX] + stemshift;
2594
2595                         /* first set stemlen to beam's Y coord minus note's */
2596                         gs_p->stemlen = (b0 + b1 * x) - BNOTE(gs_p).c[AY];
2597
2598                         /* if stems are down, reverse it */
2599                         if (gs_p->stemdir == DOWN)
2600                                 gs_p->stemlen = -(gs_p->stemlen);
2601
2602                         finalstemadjust(gs_p);
2603                 }
2604                 /* loop through the bottom staff's groups */
2605                 for (gs_p = FIRSTCSB(start2_p); gs_p != 0; gs_p=nextcsb(gs_p)){
2606                         x = gs_p->c[AX] + stemshift;
2607
2608                         /* first set stemlen to beam's Y coord minus note's */
2609                         gs_p->stemlen = (b0 + b1 * x) - BNOTE(gs_p).c[AY];
2610
2611                         /* if stems are down, reverse it */
2612                         if (gs_p->stemdir == DOWN)
2613                                 gs_p->stemlen = -(gs_p->stemlen);
2614
2615                         /* if negative (note on wrong side of beam), error */
2616                         if (gs_p->stemlen < 0) {
2617                                 l_ufatal(gs_p->inputfile, gs_p->inputlineno,
2618                                         "stem length was forced negative");
2619                         }
2620
2621                         finalstemadjust(gs_p);
2622                 }
2623         } else {        /* topdir != botdir; some stems have different dir */
2624
2625                 struct GRPSYL *prev_p;          /* previous CSB group */
2626                 struct GRPSYL *firstsub_p;      /* first group of a subbeam */
2627                 struct GRPSYL *lastsub_p;       /* last group of a subbeam */
2628                 struct GRPSYL *sub_p;           /* a group in a subbeam */
2629                 int minbeams;                   /* no. of beams all share */
2630                 int beams;                      /* no. of beams of a group */
2631                 int slowbasic;                  /* slowest basictime in CSB */
2632                 int fastbasic;                  /* fastest basictime in CSB */
2633                 int basic;                      /* a basictime value */
2634                 float bhigh;                    /* height of beams */
2635                 float extra;            /* amount to lengthen all stems by */
2636
2637
2638                 /*
2639                  * Find the minimum number of beams of the groups in the CSB
2640                  * set.  That will be the number of beams that they all share.
2641                  */
2642                 minbeams = 999;         /* way more than there could ever be */
2643                 for (gs_p = first_p; gs_p != end1_p->next;
2644                                 gs_p = nxtbmnote(gs_p, start1_p, end1_p->next)){
2645                         beams = drmo(gs_p->basictime) - 2;
2646                         if (beams < minbeams)
2647                                 minbeams = beams;
2648                 }
2649
2650                 /*
2651                  * Find height of all the beams: the distance between the
2652                  * centers of the outer beams.  This should agree with 
2653                  * the numbers in prntdata.c.
2654                  */
2655                 bhigh = (minbeams - 1) * Staffscale *
2656                         (first_p->grpsize == GS_NORMAL ? FLAGSEP : 4.0 * POINT);
2657
2658                 /*
2659                  * Change the y intercept such that the first stem is lengthened
2660                  * by half of this height.  The line is at the outer beam, from
2661                  * the perspective of the first group.
2662                  */
2663                 b0 += first_p->stemdir == UP ? bhigh / 2.0 : -bhigh / 2.0;
2664
2665                 /*
2666                  * First set stem lengths to reach the line of the main beam.
2667                  * At this point, we don't yet include the distance between the
2668                  * notes of multinote groups.  While we're at it, find the
2669                  * slowest basictime of any group in the CSB set.
2670                  * Also find the fastest basictime.
2671                  */
2672                 slowbasic = 1024;       /* faster than any could be */
2673                 fastbasic = 8;          /* slowest that any could be */
2674                 /* loop through the top staff's groups: all stems down */
2675                 for (gs_p = FIRSTCSB(start1_p); gs_p != 0; gs_p=nextcsb(gs_p)){
2676                         x = gs_p->c[AX] - stemshift;
2677
2678                         /* first set stemlen to note's Y coord minus beam's */
2679                         gs_p->stemlen = gs_p->notelist[ gs_p->nnotes - 1 ].
2680                                         c[AY] - (b0 + b1 * x);
2681
2682                         slowbasic = MIN(slowbasic, gs_p->basictime);
2683                         fastbasic = MAX(fastbasic, gs_p->basictime);
2684                 }
2685                 /* loop through the bottom staff's groups; all stems up */
2686                 for (gs_p = FIRSTCSB(start2_p); gs_p != 0; gs_p=nextcsb(gs_p)){
2687                         x = gs_p->c[AX] + stemshift;
2688
2689                         /* first set stemlen to beam's Y coord minus note's */
2690                         gs_p->stemlen = (b0 + b1 * x) - gs_p->notelist[0].c[AY];
2691
2692                         slowbasic = MIN(slowbasic, gs_p->basictime);
2693                         fastbasic = MAX(fastbasic, gs_p->basictime);
2694                 }
2695
2696                 /*
2697                  * Find the minimum number of beams (based on the slowest
2698                  * basictime) and subtract 1 to find the number of additional
2699                  * beams that all groups share beyond the first beam.  Multiply
2700                  * by the distance the centers of neighboring beams.
2701                  */
2702                 extra = ((drmo(slowbasic) - 2) - 1) * Staffscale *
2703                         (first_p->grpsize == GS_NORMAL ? FLAGSEP : 4.0 * POINT);
2704
2705                 /*
2706                  * For each group with stemdir opposite to that of the first
2707                  * group, lengthen its stemlen by that amount.
2708                  */
2709                 for (gs_p = first_p; gs_p != end1_p->next; gs_p =
2710                                 nxtbmnote(gs_p, start1_p, end1_p->next)) {
2711
2712                         if (gs_p->stemdir != first_p->stemdir)
2713                                 gs_p->stemlen += extra;
2714                 }
2715
2716                 /*
2717                  * Loop for each basictime being used that is shorter than the
2718                  * longest one; that is, for each level of subbeam that is
2719                  * needed anywhere.
2720                  */
2721                 for (basic = slowbasic * 2; basic <= fastbasic; basic *= 2) {
2722
2723                         /* loop through all note groups in the CSB */
2724                         for (prev_p = 0, gs_p = first_p;
2725                              gs_p != end1_p->next;
2726                              prev_p = gs_p, gs_p = nxtbmnote(gs_p, start1_p,
2727                                         end1_p->next)) {
2728                                 /*
2729                                  * If this group has at least as fast a basic-
2730                                  * time as the one we're now dealing with, and
2731                                  * the previous group doesn't (or there is no
2732                                  * previous group), a new subbeam must begin
2733                                  * here (or it could be just a partial beam).
2734                                  * If not, "continue" here.
2735                                  */
2736                                 if (gs_p->basictime < basic || (gs_p != first_p
2737                                                 && prev_p->basictime >= basic)){
2738                                         continue;
2739                                 }
2740
2741                                 /* point at the start of this subbeam */
2742                                 firstsub_p = gs_p;
2743
2744                                 /*
2745                                  * Set lastsub_p to right end of the subbeam,
2746                                  * the group right before the basictime becomes
2747                                  * slower than the level we are dealing with.
2748                                  */
2749                                 for (lastsub_p = sub_p = firstsub_p; sub_p !=
2750                                      end1_p->next; sub_p = nxtbmnote(sub_p,
2751                                      start1_p, end1_p->next)) {
2752
2753                                         if (sub_p == 0 ||
2754                                             sub_p->basictime < basic) {
2755                                                 break;
2756                                         }
2757                                         lastsub_p = sub_p;
2758                                 }
2759
2760                                 /*
2761                                  * Loop through subbeam, lengthening the stems
2762                                  * of all the note groups whose stem direction
2763                                  * is opposite to the first group's.  Lengthen
2764                                  * them enough for one more beam.
2765                                  */
2766                                 for (sub_p = firstsub_p; sub_p != end1_p->next;
2767                                      sub_p = nxtbmnote(sub_p, start1_p,
2768                                      end1_p->next)) {
2769
2770                                         if (sub_p->stemdir != firstsub_p->
2771                                                         stemdir) {
2772                                                 sub_p->stemlen +=
2773                                                 (sub_p->grpsize == GS_NORMAL ?
2774                                                 FLAGSEP : 4.0 * POINT) *
2775                                                 Staffscale;
2776                                         }
2777
2778                                         if (sub_p == lastsub_p) {
2779                                                 break;
2780                                         }
2781                                 }
2782                         }
2783                 }
2784
2785                 /* adjust all stems in the CSB */
2786                 for (gs_p = first_p;
2787                      gs_p != end1_p->next;
2788                      gs_p = nxtbmnote(gs_p, start1_p, end1_p->next)) {
2789
2790                         /* if negative (note on wrong side of beam), error */
2791                         if (gs_p->stemlen < 0) {
2792                                 l_ufatal(gs_p->inputfile, gs_p->inputlineno,
2793                                         "stem length was forced negative");
2794                         }
2795
2796                         /* add distance between outer notes of group */
2797                         gs_p->stemlen += (gs_p->notelist[0].stepsup -
2798                         gs_p->notelist[ gs_p->nnotes - 1 ].stepsup) * Stepsize;
2799                 }
2800
2801         }
2802
2803         /*
2804          * In beamstem.c, setgroupvert() expanded the north and south
2805          * boundaries of groups to allow for stems (except for CSB groups) and
2806          * "with" items (except for CSB where normwith was NO).  The exceptions
2807          * were because in those cases we needed to know the stem lengths and
2808          * we didn't yet.  Well, now we know.  So do the job here.
2809          *
2810          * The extension for the stem is the length of the exterior part of it
2811          * minus half the size of the stem side note (about a STEPSIZE), since
2812          * the note itself is already included in the group boundary.  Each
2813          * "with" item is allowed enough space for its height, or MINWITHHEIGHT,
2814          * whichever is greater.  In the print phase, items of height less than
2815          * MINWITHHEIGHT will be placed so as to avoid staff lines as much as
2816          * possible.
2817          */
2818         for (gs_p = first_p; gs_p != end1_p->next; gs_p = nxtbmnote(gs_p,
2819                         start1_p, end1_p->next)) {
2820                 outstem = gs_p->stemlen
2821                         - (gs_p->notelist[0].c[RY]
2822                         - gs_p->notelist[ gs_p->nnotes - 1 ].c[RY]);
2823                 if (gs_p->stemdir == UP)
2824                         gs_p->c[AN] += outstem - Stepsize;
2825                 else
2826                         gs_p->c[AS] -= outstem - Stepsize;
2827
2828                 if (gs_p->normwith == NO) {
2829                         for (n = 0; n < gs_p->nwith; n++) {
2830                                 hi = strheight(gs_p->withlist[n]);
2831                                 hi = MAX(hi, Staffscale * MINWITHHEIGHT);
2832                                 if (gs_p->stemdir == UP)
2833                                         gs_p->c[AN] += hi;
2834                                 else
2835                                         gs_p->c[AS] -= hi;
2836                         }
2837                 }
2838         }
2839 }
2840 \f
2841 /*
2842  * Name:        calcline()
2843  *
2844  * Abstract:    Calculate the equation of the line for the beams of a CSB set.
2845  *
2846  * Returns:     YES if an equation was calculated, NO if there are no stems.
2847  *
2848  * Description: This function uses linear regression to figure out where the
2849  *              best place to put the beam is, for a CSB set.  Then, based on
2850  *              whether the stems on the two staffs have the same direction, it
2851  *              calls the appropriate function to adjust the results of the
2852  *              linear regression as needed.
2853  */
2854
2855 static int
2856 calcline(start1_p, end1_p, start2_p, end2_p, first_p, last_p, topdir, botdir,
2857                 b0_p, b1_p)
2858
2859 struct GRPSYL *start1_p;        /* first group in first voice */
2860 struct GRPSYL *start2_p;        /* first group in second voice */
2861 struct GRPSYL *end1_p;          /* last group in first voice */
2862 struct GRPSYL *end2_p;          /* last group in second voice */
2863 struct GRPSYL *first_p;         /* first note group in either voice */
2864 struct GRPSYL *last_p;          /* last note group in either voice */
2865 int topdir, botdir;             /* stem directions of top and bottom voices */
2866 float *b0_p, *b1_p;             /* y intercept and slope to return */
2867
2868 {
2869         float defstemsteps;     /* default stem length */
2870         int one_end_forced;     /* is stem len forced on one end only? */
2871         int slope_forced;       /* is the slope of the beam forced? */
2872         float forced_slope;     /* slope that the user forced */
2873         struct GRPSYL *gs_p;    /* loop through the groups in the beamed set */
2874         float sx, sy;           /* sum of x and y coords of notes */
2875         float xbar, ybar;       /* average x and y coords of notes */
2876         float top, bottom;      /* numerator & denominator for finding b1 */
2877         float temp;             /* scratch variable */
2878         float b0, b1;           /* y intercept and slope */
2879         float deflen;           /* default len of a stem, based on basictime */
2880         int num;                /* number of notes */
2881
2882
2883         if (fabs(first_p->beamslope - NOBEAMANGLE) < 0.001) {
2884                 slope_forced = NO;
2885                 forced_slope = 0.0;     /* not used, keep lint happy */
2886         } else {
2887                 slope_forced = YES;
2888                 forced_slope = tan(first_p->beamslope * PI / 180.0);
2889         }
2890         one_end_forced = IS_STEMLEN_KNOWN(first_p->stemlen) !=
2891                          IS_STEMLEN_KNOWN(last_p->stemlen);
2892
2893         /*
2894          * Find how long we'd like stems to be, ignoring for the moment groups
2895          * that need to be longer due to multiple beams.
2896          */
2897         /* average default stems lengths of the two voices */
2898         defstemsteps = (vvpath(start1_p->staffno, start1_p->vno, STEMLEN)->
2899                         stemlen + 
2900                         vvpath(start2_p->staffno, start2_p->vno, STEMLEN)->
2901                         stemlen) / 2.0;
2902         /* if this is zero, both stemlens must be zero, so no stems */
2903         if (defstemsteps == 0.0 && ! slope_forced && ( ! one_end_forced ||
2904                         first_p->stemlen == 0.0 || last_p->stemlen == 0.0)) {
2905                 return (NO);
2906         }
2907         if (allsmall(start1_p, end1_p) == NO ||
2908                                 allsmall(start2_p, end2_p) == NO) {
2909                 /* at least one group has a normal size note */
2910                 deflen = defstemsteps * Stepsize;
2911         } else {
2912                 /* all groups have all small notes */
2913                 deflen = defstemsteps * SM_STEMFACTOR * Stepsize;
2914         }
2915
2916         /*
2917          * Use linear regression to find the best-fit line through where the
2918          * ends of the stems would be if they were the standard length.  In
2919          * setbeam() where a similar thing was done for non-CSB beams, we used
2920          * the centers of the notes, which was okay because at this point in
2921          * the game we're really just interested in finding the slope.  But
2922          * in CSB, sometimes the stems of the two staffs go in opposite
2923          * directions, so we really need to consider the ends of the stems.
2924          *
2925          * In this function, we will always be concerned with the X coord of
2926          * the group as a whole (disregarding any notes that are on the "wrong"
2927          * side of the stem) but the Y coord of the note of the group that's
2928          * nearest to the beam (thus the BNOTE macro).
2929          *
2930          * First get sum of x and y coords, to find averages.
2931          */
2932         sx = sy = 0;
2933         num = 0;
2934         for (gs_p = FIRSTCSB(start1_p); gs_p != 0; gs_p = nextcsb(gs_p)) {
2935                 sx += gs_p->c[AX];
2936                 sy += BNOTE(gs_p).c[AY] + (topdir == UP ? deflen : -deflen);
2937                 num++;                  /* count number of notes */
2938         }
2939         for (gs_p = FIRSTCSB(start2_p); gs_p != 0; gs_p = nextcsb(gs_p)) {
2940                 sx += gs_p->c[AX];
2941                 sy += BNOTE(gs_p).c[AY] + (botdir == UP ? deflen : -deflen);
2942                 num++;                  /* count number of notes */
2943         }
2944
2945         xbar = sx / num;
2946         ybar = sy / num;
2947
2948         /* accumulate numerator & denominator of regression formula for b1 */
2949         top = bottom = 0;
2950         for (gs_p = FIRSTCSB(start1_p); gs_p != 0; gs_p = nextcsb(gs_p)) {
2951                 temp = gs_p->c[AX] - xbar;
2952                 top += temp * (BNOTE(gs_p).c[AY] +
2953                                 (topdir == UP ? deflen : -deflen) - ybar);
2954                 bottom += temp * temp;
2955         }
2956         for (gs_p = FIRSTCSB(start2_p); gs_p != 0; gs_p = nextcsb(gs_p)) {
2957                 temp = gs_p->c[AX] - xbar;
2958                 top += temp * (BNOTE(gs_p).c[AY] +
2959                                 (botdir == UP ? deflen : -deflen) - ybar);
2960                 bottom += temp * temp;
2961         }
2962
2963         b1 = top / bottom;              /* slope */
2964         b0 = ybar - b1 * xbar;          /* y intercept */
2965
2966         /* equation of regression line:  y = b0 + b1 * x   */
2967
2968         if (topdir == botdir) {
2969                 samedir(first_p, last_p, start1_p, start2_p, end1_p, &b0, &b1,
2970                                 deflen, one_end_forced, slope_forced,
2971                                 forced_slope);
2972         } else {
2973                 oppodir(first_p, last_p, start1_p, start2_p, &b0, &b1, deflen,
2974                                 one_end_forced, slope_forced, forced_slope);
2975         }
2976
2977         /* return the calculated slope and intercept */
2978         *b0_p = b0;
2979         *b1_p = b1;
2980
2981         return (YES);
2982 }
2983 \f
2984 /*
2985  * Name:        samedir()
2986  *
2987  * Abstract:    Adjust b0 and b1 when stems are all the same direction.
2988  *
2989  * Returns:     void
2990  *
2991  * Description: This function is used in the case that the stems on the two
2992  *              staffs of the CSB have the same direction.  It is given the
2993  *              y intercept and slope of the beam as calculated by linear
2994  *              regression.  It adjusts these values if need be.  The algorithm
2995  *              is similar to the one in setbeam() in beamstem.c.  But here we
2996  *              have to deal with two linked lists of groups, and we don't have
2997  *              to deal with grace notes or alternations.
2998  */
2999
3000 static void
3001 samedir(first_p, last_p, start1_p, start2_p, end1_p, b0_p, b1_p, deflen,
3002                 one_end_forced, slope_forced, forced_slope)
3003
3004 struct GRPSYL *first_p, *last_p;        /* first and last note groups in CSB */
3005 struct GRPSYL *start1_p, *start2_p;     /* first groups of 1st & 2nd voices */
3006 struct GRPSYL *end1_p;          /* last group of 1st voice */
3007 float *b0_p, *b1_p;             /* y intercept and slope */
3008 double deflen;                  /* default len of a stem, based on group size*/
3009 int one_end_forced;             /* is stem len forced on one end only? */
3010 int slope_forced;               /* is the slope of the beam forced? */
3011 double forced_slope;            /* slope that the user forced */
3012
3013 {
3014         struct GRPSYL *gs_p;    /* loop through the groups in the beamed set */
3015         float firstx, lastx;    /* x coord of first & last note (end of stem)*/
3016         float firsty, lasty;    /* y coord of first & last note (end of stem)*/
3017         float maxb0, minb0;     /* max and min y intercepts */
3018         float stemshift;        /* x distance of stem from center of note */
3019         float b0, b1;           /* working copy of y intercept and slope */
3020         float temp;             /* temp variable */
3021         float shortdist;        /* amount of stem shortening allowed (inches)*/
3022         int bf;                 /* number of beams/flags */
3023         int shortest;           /* basictime of shortest note in group */
3024
3025
3026         /* set working copies from the original values */
3027         b0 = *b0_p;
3028         b1 = *b1_p;
3029
3030         /*
3031          * Find half the width of a note head; the stems will need to be
3032          * shifted by that amount from the center of the notes so that they
3033          * will meet the edge of the notes properly.  If the stems are up,
3034          * they will be on the right side of (normal) notes, else left.  Set
3035          * the X positions for the first and last stems.
3036          */
3037         stemshift = getstemshift(first_p);
3038         if (first_p->stemdir == DOWN)
3039                 stemshift = -stemshift;
3040         firstx = first_p->c[AX] + stemshift;    /* first group's stem */
3041         lastx = last_p->c[AX] + stemshift;      /* last group's stem */
3042
3043         /*
3044          * The original line derived by linear regression must be adjusted in
3045          * certain ways.  First, override it if the user wants that; otherwise
3046          * adjust according to the beamslope parameter.
3047          */
3048         if (slope_forced) {
3049                 b1 = forced_slope;
3050         } else {
3051                 b1 = adjslope(start1_p, b1, NO);
3052         }
3053
3054         /*
3055          * Calculate a new y intercept (b0).  First pass parallel lines
3056          * through each note, and record the maximum and minimum y intercepts
3057          * that result.
3058          */
3059         b0 = BNOTE(first_p).c[AY] - b1 * first_p->c[AX];
3060         maxb0 = minb0 = b0;             /* init to value for first note */
3061         /* look at rest of them on each of the two staffs */
3062         for (gs_p = FIRSTCSB(start1_p); gs_p != 0; gs_p = nextcsb(gs_p)) {
3063                 b0 = BNOTE(gs_p).c[AY] - b1 * gs_p->c[AX];
3064                 if (b0 > maxb0)
3065                         maxb0 = b0;
3066                 else if (b0 < minb0)
3067                         minb0 = b0;
3068         }
3069         for (gs_p = FIRSTCSB(start2_p); gs_p != 0; gs_p = nextcsb(gs_p)) {
3070                 b0 = BNOTE(gs_p).c[AY] - b1 * gs_p->c[AX];
3071                 if (b0 > maxb0)
3072                         maxb0 = b0;
3073                 else if (b0 < minb0)
3074                         minb0 = b0;
3075         }
3076
3077         /*
3078          * Find the basictime of the shortest note in the CSB set, considering
3079          * also any slashes on it.  Then update the default stem length based
3080          * on that.
3081          */
3082         shortest = 0;
3083         for (gs_p = first_p; gs_p != end1_p->next; gs_p = nxtbmnote(gs_p,
3084                         start1_p, end1_p->next)) {
3085                 bf = drmo(gs_p->basictime) - 2; /* no. of beams/flags */
3086                 bf += abs(gs_p->slash_alt);     /* slashes */
3087                 /*
3088                  * In certain cases where there are accidentals, we need to
3089                  * artificially increase bf to keep the beams from overlapping
3090                  * with the accidental.
3091                  */
3092                 if (gs_p != first_p && gs_p->stemdir == UP &&
3093                                 gs_p->notelist[0].accidental != '\0' &&
3094                                 gs_p->notelist[0].accidental != 'x' &&
3095                                 b1 > 0 && bf > 1) {
3096                         bf += 3.5 * b1 * (STEPSIZE / FLAGSEP) * ((bf > 1) +
3097                                         (gs_p->notelist[0].accidental == 'B'));
3098                 }
3099                 if (bf > shortest)
3100                         shortest = bf;
3101         }
3102
3103         if (shortest > 2) {
3104                 /* don't use "==" due to floating point roundoff error */
3105                 if (deflen > 6 * Stepsize) {
3106                         /* at least one group has a normal size note */
3107                         deflen += (shortest - 2) * Flagsep;
3108                 } else {
3109                         /* all groups have all small notes */
3110                         deflen += (shortest - 2) * 4.0 * POINT * Staffscale;
3111                 }
3112         }
3113
3114         /*
3115          * The outer edge of the beam should be deflen steps away from the
3116          * average position of the notes, as defined by the linear regression
3117          * line.  But don't allow any note to be closer than a certain number
3118          * of steps less than that, the number as given by the stemshorten parm.
3119          * We use the average of the two stemshorten values for the two voices.
3120          */
3121         shortdist = (vvpath(start1_p->staffno, start1_p->vno, STEMSHORTEN)
3122                         ->stemshorten +
3123                      vvpath(start2_p->staffno, start2_p->vno, STEMSHORTEN)
3124                         ->stemshorten) / 2.0 * Stepsize;
3125         if (first_p->stemdir == UP) {
3126                 if (maxb0 - minb0 > shortdist)
3127                         b0 = maxb0 + deflen - shortdist;
3128                 else
3129                         b0 += deflen;
3130         } else { /* DOWN */
3131                 if (maxb0 - minb0 > shortdist)
3132                         b0 = minb0 - deflen + shortdist;
3133                 else
3134                         b0 -= deflen;
3135         }
3136
3137         firsty = b0 + b1 * firstx;      /* y coord near left end of beam */
3138         lasty = b0 + b1 * lastx;        /* y coord near right end of beam */
3139
3140         /*
3141          * At this point, like setbeam(), we could force the stems of notes
3142          * that are pointing to the center of their staffs to reach that center
3143          * line.  But it's questionable whether that should be done in cross
3144          * staff beaming situations.  We choose not to.
3145          */
3146
3147         /*
3148          * If y at the ends of the beam differs by less than a step (allowing a
3149          * fudge factor for roundoff error), force the beam horizontal by
3150          * setting one end farther away from the notes.  But don't do it if the
3151          * user is forcing a particular slope.
3152          */
3153         if ( ! slope_forced && fabs(firsty - lasty) < Stepsize - 0.001) {
3154                 if (first_p->stemdir == UP) {
3155                         if (firsty > lasty) {
3156                                 lasty = firsty;
3157                         } else {
3158                                 firsty = lasty;
3159                         }
3160                 } else {        /* DOWN */
3161                         if (firsty < lasty) {
3162                                 lasty = firsty;
3163                         } else {
3164                                 firsty = lasty;
3165                         }
3166                 }
3167         }
3168
3169         /* recalculate slope and y intercept from (possibly) new endpoints */
3170         b1 = (lasty - firsty) / (lastx - firstx);       /* slope */
3171         b0 = firsty - b1 * firstx;                      /* y intercept */
3172
3173         /*
3174          * At this point, like setbeam(), we could do the equivalent of
3175          * embedgrace() and avoidothervoice().  But those functions themselves
3176          * wouldn't work here as they are, and/or we don't have the necessary
3177          * info handy for calling them.  These problems are fairly rare, on top
3178          * of cross staff beaming already being fairly rare.  If something
3179          * collides, the user can always manually set the stem lengths.
3180          */
3181
3182         /*
3183          * If one end's stem len was forced but not the other, now is the time
3184          * to apply that forcing.  So in effect, we have taken the beam as
3185          * determined by the normal algorithm and now we change the vertical
3186          * coord of this end.  If the slope was also forced, move the other
3187          * end by the same amount so that the slope won't change.
3188          */
3189         if (one_end_forced) {
3190                 if (IS_STEMLEN_KNOWN(first_p->stemlen)) {
3191                         first_p->stemlen *= Staffscale;
3192                         temp = firsty;
3193                         firsty = BNOTE(first_p).c[AY] + first_p->stemlen *
3194                                         (first_p->stemdir == UP ? 1.0 : -1.0);
3195                         if (slope_forced) {
3196                                 lasty += firsty - temp;
3197                         }
3198                 } else {
3199                         last_p->stemlen *= Staffscale;
3200                         temp = lasty;
3201                         lasty = BNOTE(last_p).c[AY] + last_p->stemlen *
3202                                         (last_p->stemdir == UP ? 1.0 : -1.0);
3203                         if (slope_forced) {
3204                                 firsty += lasty - temp;
3205                         }
3206                 }
3207
3208                 /* recalculate */
3209                 b1 = (lasty - firsty) / (lastx - firstx); /* slope */
3210                 b0 = firsty - b1 * firstx;              /* y intercept */
3211         }
3212
3213         /* send back the newly calculated values */
3214         *b0_p = b0;
3215         *b1_p = b1;
3216 }
3217 \f
3218 /*
3219  * Name:        oppodir()
3220  *
3221  * Abstract:    Adjust b0 and b1 when stems are in opposite directions.
3222  *
3223  * Returns:     void
3224  *
3225  * Description: This function is used in the case that the stems on the two
3226  *              staffs of the CSB all have opposite directions.  It is given
3227  *              the y intercept and slope of the beam as calculated by linear
3228  *              regression.  It adjusts these values if need be.
3229  */
3230
3231 static void
3232 oppodir(first_p, last_p, start1_p, start2_p, b0_p, b1_p, deflen,
3233                 one_end_forced, slope_forced, forced_slope)
3234
3235 struct GRPSYL *first_p, *last_p;        /* first and last note groups in CSB */
3236 struct GRPSYL *start1_p, *start2_p;     /* first groups of 1st & 2nd voices */
3237 float *b0_p, *b1_p;             /* y intercept and slope */
3238 double deflen;                  /* default len of a stem, based on group size*/
3239 int one_end_forced;             /* is stem len forced on one end only? */
3240 int slope_forced;               /* is the slope of the beam forced? */
3241 double forced_slope;            /* slope that the user forced */
3242
3243 {
3244         struct GRPSYL *gs_p;    /* loop through the groups in the beamed set */
3245         float firstx, lastx;    /* x coord of first & last note (end of stem)*/
3246         float firsty, lasty;    /* y coord of first & last note (end of stem)*/
3247         float maxb0, minb0;     /* max and min y intercepts */
3248         float stemshift;        /* x distance of stem from center of note */
3249         float b0, b1;           /* working copy of y intercept and slope */
3250         float temp;             /* temp variable */
3251
3252
3253         /* set working copies from the original values */
3254         b0 = *b0_p;
3255         b1 = *b1_p;
3256
3257         /*
3258          * Find half the width of a note head; the stems will need to be
3259          * shifted by that amount from the center of the notes so that they
3260          * will meet the edge of the notes properly.  If the stems are up,
3261          * they will be on the right side of (normal) notes, else left.  Set
3262          * the X positions for the first and last stems.
3263          */
3264         stemshift = getstemshift(first_p);
3265         if (first_p->stemdir == DOWN)
3266                 stemshift = -stemshift;
3267         firstx = first_p->c[AX] + stemshift;    /* first group's stem */
3268         lastx = last_p->c[AX] + stemshift;      /* last group's stem */
3269
3270         /*
3271          * The original line derived by linear regression must be adjusted in
3272          * certain ways.  First, override it if the user wants that; otherwise
3273          * adjust according to the beamslope parameter.
3274          */
3275         if (slope_forced) {
3276                 b1 = forced_slope;
3277         } else {
3278                 b1 = adjslope(start1_p, b1, YES);
3279         }
3280
3281         /*
3282          * Calculate a new y intercept (b0).  First pass parallel lines
3283          * through each note, and record the minimum y intercept for the top
3284          * staff and the maximum for the bottom staff that result.
3285          */
3286         minb0 = 1000.0;         /* init way positive */
3287         /* look at rest of them on each of the two staffs */
3288         for (gs_p = FIRSTCSB(start1_p); gs_p != 0; gs_p = nextcsb(gs_p)) {
3289                 b0 = BNOTE(gs_p).c[AY] - b1 * gs_p->c[AX];
3290                 if (b0 < minb0)
3291                         minb0 = b0;
3292         }
3293         maxb0 = -1000.0;        /* init way negative */
3294         for (gs_p = FIRSTCSB(start2_p); gs_p != 0; gs_p = nextcsb(gs_p)) {
3295                 b0 = BNOTE(gs_p).c[AY] - b1 * gs_p->c[AX];
3296                 if (b0 > maxb0)
3297                         maxb0 = b0;
3298         }
3299
3300         /*
3301          * Make the y intercept be the average of these.  That means the top
3302          * staff's shortest stem will be equal in length to the bottom staff's.
3303          */
3304         b0 = (maxb0 + minb0) / 2.0;
3305
3306         firsty = b0 + b1 * firstx;      /* y coord near left end of beam */
3307         lasty = b0 + b1 * lastx;        /* y coord near right end of beam */
3308
3309         /*
3310          * If y at the ends of the beam differs by less than a step (allowing a
3311          * fudge factor for roundoff error), force the beam horizontal,
3312          * averaging the two values.
3313          */
3314         if ( ! slope_forced && fabs(firsty - lasty) < Stepsize - 0.001) {
3315                 lasty = (firsty + lasty) / 2.;
3316                 firsty = lasty;
3317         }
3318
3319         /* recalculate slope and y intercept from (possibly) new endpoints */
3320         b1 = (lasty - firsty) / (lastx - firstx);       /* slope */
3321         b0 = firsty - b1 * firstx;                      /* y intercept */
3322
3323         /*
3324          * If one end's stem len was forced but not the other, now is the time
3325          * to apply that forcing.  So in effect, we have taken the beam as
3326          * determined by the normal algorithm and now we change the vertical
3327          * coord of this end.  If the slope was also forced, move the other
3328          * end by the same amount so that the slope won't change.
3329          */
3330         if (one_end_forced) {
3331                 if (IS_STEMLEN_KNOWN(first_p->stemlen)) {
3332                         first_p->stemlen *= Staffscale;
3333                         temp = firsty;
3334                         firsty = BNOTE(first_p).c[AY] + first_p->stemlen *
3335                                         (first_p->stemdir == UP ? 1.0 : -1.0);
3336                         if (slope_forced) {
3337                                 lasty += firsty - temp;
3338                         }
3339                 } else {
3340                         last_p->stemlen *= Staffscale;
3341                         temp = lasty;
3342                         lasty = BNOTE(last_p).c[AY] + last_p->stemlen *
3343                                         (last_p->stemdir == UP ? 1.0 : -1.0);
3344                         if (slope_forced) {
3345                                 firsty += lasty - temp;
3346                         }
3347                 }
3348
3349                 /* recalculate */
3350                 b1 = (lasty - firsty) / (lastx - firstx); /* slope */
3351                 b0 = firsty - b1 * firstx;              /* y intercept */
3352         }
3353
3354         /* send back the newly calculated values */
3355         *b0_p = b0;
3356         *b1_p = b1;
3357 }
3358 \f
3359 /*
3360  * Name:        nextcsb()
3361  *
3362  * Abstract:    Find the next note group on this staff in this CSB.
3363  *
3364  * Returns:     pointer to next note group in CSB on this staff, 0 if none
3365  *
3366  * Description: This function looks for the next group on this staff that is
3367  *              still in this CSB set (therefore nongrace), and contains notes
3368  *              (not a space).
3369  */
3370
3371 static struct GRPSYL *
3372 nextcsb(gs_p)
3373
3374 struct GRPSYL *gs_p;            /* current group, must be in a CSB */
3375
3376 {
3377         /* if we are already at the last group in the set, no next group */
3378         if (gs_p->beamloc == ENDITEM)
3379                 return (0);
3380
3381         /* loop forward, considering only nongrace groups */
3382         for (gs_p = nextnongrace(gs_p); gs_p != 0; gs_p = nextnongrace(gs_p)) {
3383                 /* if we find a note group, return it */
3384                 if (gs_p->grpcont == GC_NOTES)
3385                         return (gs_p);
3386                 /* must be a space (rests not allowed); if enditem, give up */
3387                 if (gs_p->beamloc == ENDITEM)
3388                         return (0);
3389         }
3390
3391         return (0);     /* hit the end of the measure (shouldn't happen) */
3392 }
3393 \f
3394 /*
3395  * Name:        nxtbmnote()
3396  *
3397  * Abstract:    Find the next note group in this CSB (this staff or the other).
3398  *
3399  * Returns:     pointer to next note group in CSB, endnext_p if none
3400  *
3401  * Description: This function looks for the next group that is still in this
3402  *              CSB set (therefore nongrace), and contains notes (not a space
3403  *              or a rest), whichever staff it may be on.
3404  */
3405
3406 static struct GRPSYL *
3407 nxtbmnote(gs_p, first_p, endnext_p)
3408
3409 struct GRPSYL *gs_p;            /* current group, must be in a CSB */
3410 struct GRPSYL *first_p;         /* first group in top staff of the CSB */
3411 struct GRPSYL *endnext_p;       /* what to return if we hit the end */
3412
3413 {
3414         /*
3415          * Keep finding the next nonspace group, until we hit the end or we
3416          * find one that is not a rest.
3417          */
3418         do {
3419                 gs_p = nxtbmgrp(gs_p, first_p, endnext_p);
3420         } while (gs_p != endnext_p && gs_p->grpcont != GC_NOTES);
3421         return (gs_p);
3422 }