chiark / gitweb /
Import upstream version 5.3.
[mup] / mup / mup / beamstem.c
1 /* Copyright (c) 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005 by Arkkra Enterprises */
2 /* All rights reserved */
3 /*
4  * Name:        beamstem.c
5  *
6  * Description: This file contains functions for setting lengths of note
7  *              stems, which also involves beaming considerations.
8  */
9
10 #include "defines.h"
11 #include "structs.h"
12 #include "globals.h"
13
14 /*
15  * Several functions need to know the value of the "stemlen" parameter, so
16  * instead of them all calling vvpath, define a holding place here.
17  */
18 static float Defstemsteps;
19
20 static void proclist P((struct MAINLL *mainll_p, int vno));
21 static void proctablist P((struct MAINLL *mainll_p, int vno));
22 static int stemforced P((struct GRPSYL *gs_p, struct GRPSYL *ogs_p));
23 static void setbeam P((struct GRPSYL *start_p, struct GRPSYL *end_p,
24                 struct GRPSYL *ogs_p)); 
25 static void restore_ry P((struct GRPSYL *start_p, struct GRPSYL *end_p));
26 static double embedgrace P((struct GRPSYL *start_p, double b1, double b0));
27 static double embedclef P((struct GRPSYL *start_p, double b1, double b0));
28 static double beamoff P((struct GRPSYL *gs_p, int side, double boundary,
29                 struct GRPSYL *start_p));
30 static void embedrest P((struct GRPSYL *start_p, struct GRPSYL *last_p,
31                 double b1, double b0));
32 static double avoidothervoice P((struct GRPSYL *start_p, struct GRPSYL *last_p,
33                 double b1, double b0, struct GRPSYL *ogs_p));
34 static void setgroupvert P((int, struct GRPSYL *, struct GRPSYL *));
35 static void settuplet P((struct GRPSYL *start_p, struct STAFF *staff_p));
36 static void expgroup P((struct GRPSYL *gs_p, struct GRPSYL *ogs_p));
37 static void applywith P((struct GRPSYL *gs_p, int side));
38 \f
39 /*
40  * Name:        beamstem()
41  *
42  * Abstract:    Set stem lengths for all notes that have stems or slash/alt.
43  *
44  * Returns:     void
45  *
46  * Description: This function loops through the main linked list.  For each
47  *              linked list of groups on each visible staff, it calls proclist
48  *              to set stem lengths.
49  */
50
51 void
52 beamstem()
53
54 {
55         register struct MAINLL *mainll_p; /* point along main linked list */
56         int n;                          /* loop variable */
57
58
59         debug(16, "beamstem CSSpass=%d", CSSpass);
60         initstructs();                  /* clean out old SSV info */
61
62         /*
63          * Loop once for each item in the main linked list.  Apply any SSVs
64          * that are found.
65          */
66         for (mainll_p = Mainllhc_p; mainll_p != 0; mainll_p = mainll_p->next) {
67                 if (mainll_p->str == S_SSV) {
68
69                         asgnssv(mainll_p->u.ssv_p);
70
71                 } else if (mainll_p->str == S_STAFF &&
72                                 mainll_p->u.staff_p->visible == YES &&
73                                 ! is_mrpt(mainll_p->u.staff_p->groups_p[0])) {
74                         /*
75                          * For this visible staff, call a subroutine to process
76                          * each list of groups on it.
77                          */
78                         for (n = 0; n < MAXVOICES; n++) {
79                                 if (mainll_p->u.staff_p->groups_p[n] != 0) {
80                                         /* set global default stem steps */
81                                         Defstemsteps = vvpath(mainll_p->
82                                                 u.staff_p->staffno,
83                                                 n + 1, STEMLEN)->stemlen;
84                                         if (is_tab_staff(mainll_p->u.staff_p->
85                                                         staffno)) {
86                                                 proctablist(mainll_p, n);
87                                         } else {
88                                                 proclist(mainll_p, n);
89                                         }
90                                 }
91                         }
92                 }
93         }
94 }
95 \f
96 /*
97  * Name:        proclist()
98  *
99  * Abstract:    Process linked list of groups.
100  *
101  * Returns:     void
102  *
103  * Description: This function loops through the linked list of groups for one
104  *              voice for one measure, first handling the grace groups, then
105  *              doing a second loop for the nongrace groups.  For each non-
106  *              beamed note that needs it, it sets the stem length.  For each
107  *              beamed group, it calls setbeam to figure out the equation
108  *              of the beam, and set the stem lengths accordingly.  It also
109  *              sets the relative vertical coords of the groups.  These coords
110  *              then get altered to include "with" lists and tuplet marks.
111  */
112
113 static void
114 proclist(mainll_p, vno)
115
116 struct MAINLL *mainll_p;        /* MLL struct for staff we're dealing with */
117 int vno;                        /* voice we're to deal with, 0 to MAXVOICES-1 */
118
119 {
120         struct GRPSYL *gs_p;    /* point to first group in a linked list */
121         struct GRPSYL *ogs_p;   /* point to first group in other linked list */
122         struct STAFF *staff_p;  /* point to the staff it's connected to */
123         struct GRPSYL *savegs_p;/* save incoming gs_p */
124         struct GRPSYL *beamst_p;/* point at first group of a beamed set */
125         float notedist;         /* distance between outer notes of a group */
126         float defsteps;         /* additional default steps long to make stem*/
127         int bf;                 /* number of beams/flags */
128
129
130         debug(32, "proclist file=%s line=%d vno=%d", mainll_p->inputfile,
131                         mainll_p->inputlineno, vno);
132         /*
133          * Set pointers to 1st group in our list and in the "other" list, as
134          * appropriate.  Voices 1 and 2 (vno=0,1) refer to each other as the
135          * "other" voice.  (If there is only one voice, ogs_p is set to voice 2
136          * (vno=1) which is a null pointer.)  Voice 3 (vno=2) always ignores
137          * the other voices, so for it, ogs_p is a null pointer.
138          */
139         gs_p = mainll_p->u.staff_p->groups_p[ vno ];
140         ogs_p = vno == 2 ? (struct GRPSYL *)0 :
141                         mainll_p->u.staff_p->groups_p[ ! vno ];
142
143         staff_p = mainll_p->u.staff_p;  /* also point at staff */
144
145         /* set globals like Staffscale for use by the rest of the file */
146         set_staffscale(staff_p->staffno);
147
148         beamst_p = 0;   /* prevent useless 'used before set' warnings */
149
150         /*
151          * Loop through every group, skipping rests, spaces, and nongrace
152          * groups, setting the stem length of grace groups.
153          */
154         for (savegs_p = gs_p; gs_p != 0; gs_p = gs_p->next) {
155                 if (gs_p->grpcont != GC_NOTES)
156                         continue;
157                 if (gs_p->grpvalue == GV_NORMAL)
158                         continue;
159
160                 /*
161                  * If we are at the start of a beamed set of groups, remember
162                  * this place.  Then, when we find the end of the set, call
163                  * setbeam to figure out the equation of the beam and set the
164                  * stem lengths.
165                  */
166                 if (gs_p->beamloc != NOITEM) {
167                         if (gs_p->beamloc == STARTITEM)
168                                 beamst_p = gs_p;
169                         if (gs_p->beamloc == ENDITEM)
170                                 setbeam(beamst_p, nextsimilar(gs_p), ogs_p);
171
172                         continue;
173                 }
174
175                 /* if we get here, this group is not in a beamed set */
176
177                 /* if not affected by CSS, do on normal pass, and only then */
178                 /* if affected by CSS, do on CSS pass, and only then */
179                 if (css_affects_stemtip(gs_p) != CSSpass) {
180                         continue;
181                 }
182
183                 /*
184                  * If the user specified a nonzero stem length, that's only the
185                  * part of it that's not between the notes.  So add the distance
186                  * between the outer notes of the group.  However, if they
187                  * specified 0, they should get no stem.
188                  */
189                 if (IS_STEMLEN_KNOWN(gs_p->stemlen)) {
190                         if (gs_p->stemlen != 0.0) {
191                                 gs_p->stemlen *= Staffscale;
192                                 notedist = gs_p->notelist[0].c[RY] - gs_p->
193                                         notelist[ gs_p->nnotes - 1 ].c[RY];
194                                 gs_p->stemlen += notedist;
195                         }
196                         continue;
197                 }
198
199                 /*
200                  * Grace quarter notes default to just a note head and no stem.
201                  * So set their stem length to 0.
202                  */
203                 if (gs_p->basictime == 4) {
204                         gs_p->stemlen = 0;
205                         continue;
206                 }
207
208                 /*
209                  * If stemlen parm is zero, force length to zero.  This will
210                  * look bad for non-quarter notes, but that's what they
211                  * asked for.
212                  */
213                 if (Defstemsteps == 0.0) {
214                         gs_p->stemlen = 0.0;
215                         continue;
216                 }
217
218                 /*
219                  * Set the stems to the requested length, plus the distance
220                  * between the highest and lowest note of the group, except
221                  * longer for notes with more than 2 flags or beams.  Unlike
222                  * nongrace groups, stems need not reach the center line of
223                  * the staff.
224                  */
225                 /* find distance between outer notes of the group */
226                 notedist = gs_p->notelist[0].c[RY] -
227                         gs_p->notelist[ gs_p->nnotes - 1 ].c[RY];
228
229                 /* set len to default length + distance between outer notes */
230                 gs_p->stemlen = (Defstemsteps * SM_STEMFACTOR) * Stepsize +
231                                 notedist;
232
233                 bf = drmo(gs_p->basictime) - 2; /* no. of beams/flags */
234                 if (bf > 2)
235                         gs_p->stemlen += (bf - 2) * Smflagsep;
236         }
237
238         /*
239          * Loop through every grace group, skipping rests and spaces,
240          * setting the relative vertical coordinates.
241          */
242         setgroupvert(GV_ZERO, savegs_p, ogs_p);
243
244         /*
245          * Loop through every group, skipping rests, spaces and grace groups,
246          * setting the stem length of all nongrace groups.
247          *
248          * WARNING:  The code in this loop is similar to stemroom() in
249          * setgrps.c.  If you change one, you probably will need to change
250          * the other.
251          */
252         for (gs_p = savegs_p; gs_p != 0; gs_p = gs_p->next) {
253                 if (gs_p->grpcont != GC_NOTES)
254                         continue;
255                 if (gs_p->grpvalue == GV_ZERO)
256                         continue;
257                 /*
258                  * If this is cross staff beaming, don't do anything now.  We
259                  * can't do anything until the absolute vertical coords are set
260                  * in absvert.c.
261                  */
262                 if (gs_p->beamto != CS_SAME) {
263                         continue;
264                 }
265
266                 /*
267                  * If we are at the start of a beamed set of groups, remember
268                  * this place.  Then, when we find the end of the set, call
269                  * setbeam to figure out the equation of the beam and set the
270                  * stem lengths.
271                  */
272                 if (gs_p->beamloc != NOITEM) {
273                         if (gs_p->beamloc == STARTITEM)
274                                 beamst_p = gs_p;
275                         if (gs_p->beamloc == ENDITEM)
276                                 setbeam(beamst_p, nextsimilar(gs_p), ogs_p);
277                         continue;
278                 }
279
280                 /* if we get here, this group is not in a beamed set */
281
282                 /* if not affected by CSS, do on normal pass, and only then */
283                 /* if affected by CSS, do on CSS pass, and only then */
284                 if (css_affects_stemtip(gs_p) != CSSpass) {
285                         continue;
286                 }
287
288                 /*
289                  * Only half notes and shorter have stems, but whole and double
290                  * whole notes still need to have a pseudo stem length set if
291                  * alternation beams are to be drawn between two neighboring
292                  * groups, or the group has slashes.
293                  */
294                 if (gs_p->basictime <= 1 && gs_p->slash_alt == 0)
295                         continue;       /* no stem and no pseudo stem */
296
297                 /*
298                  * If the user specified a nonzero stem length, that's only the
299                  * part of it that's not between the notes.  So add the distance
300                  * between the outer notes of the group.  But if they specified
301                  * 0, leave it as 0.
302                  */
303                 if (IS_STEMLEN_KNOWN(gs_p->stemlen)) {
304                         if (gs_p->stemlen == 0.0)
305                                 continue;
306
307                         gs_p->stemlen *= Staffscale;
308                         notedist = gs_p->notelist[0].c[RY] -
309                                 gs_p->notelist[ gs_p->nnotes - 1 ].c[RY];
310                         gs_p->stemlen += notedist;
311                         continue;
312                 }
313
314                 /* if stemlen parm is zero, force length to zero */
315                 if (Defstemsteps == 0.0) {
316                         gs_p->stemlen = 0.0;
317                         continue;
318                 }
319
320                 /* 
321                  * Set the stems initially to one octave long (or 5 stepsizes
322                  * for cue notes), plus the distance between the highest and
323                  * lowest note of the group, except longer for notes with more
324                  * than 2 flags or beams.  In any case, for normal sized notes,
325                  * real stems must reach the center line of the staff in most
326                  * cases.
327                  */
328                 /* find distance between outer notes of the group */
329                 notedist = gs_p->notelist[0].c[RY] -
330                         gs_p->notelist[ gs_p->nnotes - 1 ].c[RY];
331                 /* set len to default length + distance between outer notes */
332                 defsteps = Defstemsteps *
333                         (allsmall(gs_p, gs_p) == YES ? SM_STEMFACTOR : 1.0);
334                 gs_p->stemlen = defsteps * Stepsize + notedist;
335
336                 /* add more, if needed, for flags/beams/slashes/alternations */
337                 if (gs_p->basictime >= 8)
338                         bf = drmo(gs_p->basictime) - 2; /* no. of beams/flags*/
339                 else
340                         bf = 0;                 /* none on quarter or longer */
341                 bf += abs(gs_p->slash_alt);     /* slashes or alternations */
342                 if (gs_p->slash_alt > 0 && gs_p->basictime >= 16)
343                         bf++;   /* slashes need an extra one if 16, 32, ... */
344                 if (bf > 2)
345                         gs_p->stemlen += (bf - 2) * Flagsep;
346
347                 /*
348                  * If the note may have flag(s), stem up, and has dot(s), we
349                  * must prevent the flag(s) from hitting the dot(s), by
350                  * lengthening the stem.
351                  */
352                 if (gs_p->basictime >= 8 && gs_p->stemdir == UP &&
353                                 gs_p->dots != 0) {
354                         if (gs_p->notelist[0].stepsup % 2 == 0) {
355                                 /* note is on a line */
356                                 if (gs_p->basictime == 8)
357                                         gs_p->stemlen += Stepsize;
358                                 else
359                                         gs_p->stemlen += 2 * Stepsize;
360                         } else {
361                                 /* note is on a space */
362                                 if (gs_p->basictime > 8)
363                                         gs_p->stemlen += Stepsize;
364                         }
365                 }
366
367                 /*
368                  * Real (printed) stems must reach the center line for normal
369                  * groups, though they need not for cue groups or voice 3 or
370                  * when the stem direction has been forced the "wrong way" or
371                  * when all the notes are on another staff.
372                  */
373                 if (gs_p->basictime >= 2 && gs_p->grpsize == GS_NORMAL &&
374                                 vno != 2 && stemforced(gs_p, ogs_p) == NO &&
375                                 NNN(gs_p) > 0) {
376
377                         if (gs_p->stemdir == UP && gs_p->notelist[ gs_p->nnotes
378                                         - 1 ].c[RY] < -(gs_p->stemlen)) {
379                                 gs_p->stemlen = -gs_p->notelist[ gs_p->nnotes-1
380                                                 ].c[RY];
381                         }
382
383                         if (gs_p->stemdir == DOWN && gs_p->notelist[ 0 ].c[RY]
384                                                 > gs_p->stemlen) {
385                                 gs_p->stemlen = gs_p->notelist[ 0 ].c[RY];
386                         }
387                 }
388         }
389
390         /*
391          * Loop through every nongrace group, skipping rests and spaces,
392          * setting the relative vertical coordinates.
393          */
394         setgroupvert(GV_NORMAL, savegs_p, ogs_p);
395
396         /*
397          * Loop through every group, looking for tuplets.  When encountering
398          * the first item in a tuplet, call a subroutine to figure out where
399          * the bracket should go, and based on that alter the RN or RS of
400          * the groups in the tuplet.  However, if this is a tuplet whose
401          * number and bracket are not to be printed, don't call the subrountine.
402          * Also, it should not be done when there is cross staff beaming.  Mup
403          * does not automatically print tuplet numbers or brackets in CSB sets.
404          */
405         for (gs_p = savegs_p; gs_p != 0; gs_p = gs_p->next) {
406                 if ((gs_p->tuploc == STARTITEM || gs_p->tuploc == LONEITEM) &&
407                     gs_p->beamto == CS_SAME && gs_p->printtup != PT_NEITHER)
408                         settuplet(gs_p, staff_p);
409         }
410 }
411 \f
412 /*
413  * Name:        proctablist()
414  *
415  * Abstract:    Process linked list of groups on a tablature staff.
416  *
417  * Returns:     void
418  *
419  * Description: This function loops through the linked list of groups for one
420  *              measure of a tablature staff.  It sets the relative vertical
421  *              coords of the groups.  These coords then get altered to include
422  *              "with" lists and tuplet marks.
423  */
424
425 static void
426 proctablist(mainll_p, vno)
427
428 struct MAINLL *mainll_p;        /* MLL struct for staff we're dealing with */
429 int vno;                        /* voice we're to deal with, 0 to MAXVOICES-1 */
430
431 {
432         struct GRPSYL *gs_p;    /* point to first group in a linked list */
433         struct GRPSYL *ogs_p;   /* point to first group in other linked list */
434         int stepdiff;           /* steps between highest & lowest of a group */
435         int defsteps;           /* additional default steps long to make stem*/
436         int bf;                 /* number of beams/flags (really slashes) */
437
438
439         debug(32, "proctablist file=%s line=%d", mainll_p->inputfile,
440                         mainll_p->inputlineno);
441         /* no such thing as cross staff stemming for tab */
442         if (CSSpass == YES) {
443                 return;
444         }
445
446         /*
447          * Set pointers to 1st group in our list and in the "other" list, as
448          * appropriate.  Voices 1 and 2 (vno=0,1) refer to each other as the
449          * "other" voice.  (If there is only one voice, ogs_p is set to voice 2
450          * (vno=1) which is a null pointer.)  Voice 3 (vno=2) always ignores
451          * the other voices, so for it, ogs_p is a null pointer.
452          */
453         gs_p = mainll_p->u.staff_p->groups_p[ vno ];
454         ogs_p = vno == 2 ? (struct GRPSYL *)0 :
455                         mainll_p->u.staff_p->groups_p[ ! vno ];
456
457         /*
458          * Loop through every group, setting some group vertical coordinates.
459          */
460         for ( ; gs_p != 0; gs_p = gs_p->next) {
461                 /*
462                  * Just as for nontablature groups, RY is always 0, the center
463                  * of the staff, even if it falls outside the group's
464                  * rectangle.  RN and RS were set in locllnotes() and
465                  * intertab() in setnotes.c. 
466                  */
467                 gs_p->c[RY] = 0;
468
469                 /*
470                  * Slashes and "with" lists are allowed only if there are
471                  * frets, so if there aren't any frets, skip the rest.
472                  */
473                 if (gs_p->grpcont != GC_NOTES || gs_p->nnotes == 0)
474                         continue;
475
476                 /*
477                  * No tab groups have stems, but we still need to set a pseudo
478                  * stem length if the group has slashes and otherwise 0.
479                  */
480                 if (gs_p->slash_alt == 0) {
481                         gs_p->stemlen = 0;      /* no slashes */
482                 } else {
483                         /* find distance between outer frets of the group */
484                         stepdiff = gs_p->notelist[0].stepsup -
485                                 gs_p->notelist[ gs_p->nnotes - 1 ].stepsup;
486
487                         /* default length + distance between outer notes */
488                         defsteps = Defstemsteps * (allsmall(gs_p, gs_p) == YES
489                                         ? SM_STEMFACTOR : 1.0);
490                         gs_p->stemlen = stepdiff * Stepsize * TABRATIO +
491                                         defsteps * Stepsize;
492
493                         bf = abs(gs_p->slash_alt);      /* slashes */
494                         if (gs_p->basictime >= 16)
495                                 bf++;   /* slashes need extra 1 if 16, 32, ...*/
496                         if (bf > 2)
497                                 gs_p->stemlen += (bf - 2) * Flagsep;
498
499                         if (gs_p->stemdir == UP) {
500                                 gs_p->c[RN] = gs_p->notelist[gs_p->nnotes - 1]
501                                                 .c[RN] + gs_p->stemlen;
502                         } else {
503                                 gs_p->c[RS] = gs_p->notelist[0]
504                                                 .c[RY] - gs_p->stemlen;
505                         }
506                 }
507
508                 /* decrease RS based on "with" lists */
509                 expgroup(gs_p, ogs_p);
510         }
511 }
512 \f
513 /*
514  * Name:        stemforced()
515  *
516  * Abstract:    Did the user force stem(s) to go the wrong way?
517  *
518  * Returns:     YES     at least one group was forced
519  *              NO      no groups were forced
520  *
521  * Description: This function figures out whether the user forced *gs_p's stem
522  *              to go DOWN for voice 1 or UP for voice 2 when the vscheme and
523  *              the other voice would normally prevent it; or if *gs_p is at
524  *              the start of a beamed set, it checks this for all groups in
525  *              the set.
526  */
527
528 static int
529 stemforced(gs_p, ogs_p)
530
531 struct GRPSYL *gs_p;            /* the group we are asking about */
532 struct GRPSYL *ogs_p;           /* first group in other voice's linked list */
533
534 {
535         RATIONAL starttime;     /* of the group in question */
536         RATIONAL endtime;       /* of the group in question */
537         struct GRPSYL *gs2_p;   /* loop through groups */
538
539
540         /* voice 3 never cares, so is never considered to be forced */
541         if (gs_p->vno == 3) {
542                 return (NO);
543         }
544
545         /* grace cannot be forced */
546         if (gs_p->grpvalue == GV_ZERO) {
547                 return (NO);
548         }
549
550         switch (svpath(gs_p->staffno, VSCHEME)->vscheme) {
551         case V_1:
552                 return (NO);    /* no forcing is needed in this vscheme */
553         case V_2OPSTEM:
554         case V_3OPSTEM:
555                 /*
556                  * If and only if a stem is backwards, we are forced.  Note
557                  * that even for the beamed case, we only have to check one
558                  * group, since all stems in the set go the same direction.
559                  */
560                 if (gs_p->vno == 1 && gs_p->stemdir == DOWN ||
561                     gs_p->vno == 2 && gs_p->stemdir == UP) {
562                         return (YES);
563                 }
564                 return (NO);
565         }
566
567         /*
568          * We are in one of the freestem vschemes.
569          */
570
571         /* if the other voice doesn't exist, we know we were not forced */
572         if (ogs_p == 0) {
573                 return (NO);    /* other voice does not exist */
574         }
575
576         /* if all stems are normal, we are not forced (only need to check 1) */
577         if (gs_p->vno == 1 && gs_p->stemdir == UP ||
578             gs_p->vno == 2 && gs_p->stemdir == DOWN) {
579                 return (NO);
580         }
581
582         /* check if the other voice is all spaces during this time */
583
584         /* find start time of *gs_p by summing all previous groups */
585         starttime = Zero;
586         for (gs2_p = gs_p->prev; gs2_p != 0; gs2_p = gs2_p->prev) {
587                 starttime = radd(starttime, gs2_p->fulltime);
588         }
589
590         /* find end time of *gs_p (or the whole beamed set) */
591         endtime = starttime;
592         for (gs2_p = gs_p; gs2_p != 0; gs2_p = gs2_p->next) {
593                 endtime = radd(endtime, gs2_p->fulltime);
594                 if (gs2_p->beamloc == NOITEM || gs2_p->beamloc == ENDITEM &&
595                                                 gs_p->grpvalue != GV_ZERO) {
596                         break;
597                 }
598         }
599
600         if (hasspace(ogs_p, starttime, endtime) == YES) {
601                 return (NO);    /* all spaces, forcing was not needed */
602         } else {
603                 return (YES);   /* notes/rests, we were forced */
604         }
605 }
606 \f
607 /*
608  * Name:        setbeam()
609  *
610  * Abstract:    Set stem lengths for a beamed set of groups.
611  *
612  * Returns:     void
613  *
614  * Description: This function uses linear regression to figure out where the
615  *              best place to put the beam is, for a beamed set of groups, or
616  *              two groups that are alted together.  (Although there are
617  *              special cases where the beam needs to be forced horizontal
618  *              instead of using linear regression.)  But if the user specified
619  *              the stem lengths of the first and last group, it just goes with
620  *              that, instead of using linear regression.  It then sets the
621  *              stem lengths for all the groups in the set.
622  *
623  *              Groups involved in cross staff beaming should never call here.
624  *              That work must be done later in absvert.c.
625  */
626
627 static void
628 setbeam(start_p, end_p, ogs_p)
629
630 struct GRPSYL *start_p;         /* first in beamed set */
631 struct GRPSYL *end_p;           /* after last in beamed set */
632 struct GRPSYL *ogs_p;           /* first group in other voice's GRPSYL list */
633
634 {
635         struct GRPSYL *gs_p;    /* loop through the groups in the beamed set */
636         struct GRPSYL *last_p;  /* point at last valid group before end_p */
637         float sx, sy;           /* sum of x and y coords of notes */
638         float xbar, ybar;       /* average x and y coords of notes */
639         float top, bottom;      /* numerator & denominator for finding b1 */
640         float temp;             /* scratch variable */
641         float startx, endx;     /* x coord of first and last note */
642         float starty, endy;     /* y coord of first and last note */
643         float b0, b1;           /* y intercept and slope */
644         float maxb0, minb0;     /* max and min y intercepts */
645         float stemshift;        /* x distance of stem from center of note */
646         float deflen;           /* default len of a stem, based on basictime */
647         float shortdist;        /* amount of stem shortening allowed (inches)*/
648         float x;                /* x coord of a stem */
649         int css_affects_beam;   /* does CSS affect the position of the beam? */
650         int all_notes_other_staff; /* all notes in all groups on other staff */
651         int one_end_forced;     /* is stem len forced on one end only? */
652         int slope_forced;       /* is the slope of the beam forced? */
653         float forced_slope;     /* slope that the user forced */
654         int bf;                 /* number of beams/flags */
655         int shortest;           /* basictime of shortest note in group */
656         int num;                /* number of notes */
657         short *steps;           /* stepsup of beamside notes */
658         int patlen;             /* length of a pattern of notes */
659         int match;              /* does the pattern match? */
660         int k;                  /* loop variable */
661         int n;                  /* loop variable */
662
663
664         /*
665          * Find whether CSS affects the position of the beam, and whether all
666          * groups have all their notes on the other staff.  css_affects_stemtip
667          * asks (for this beamed case) whether any group's other-staff notes
668          * are stemside; that is, whether the stem points to the other staff,
669          * because then obviously the coord of the stem tip depends on where
670          * those notes are.  If all of this group's notes are on the other
671          * staff, you might expect that we would have to regard the stem tip as
672          * affected even if the stem is towards the normal staff.  But we
673          * prefer to pretend they aren't, so that we can handle more beamed
674          * sets on the first pass.  We fake out those groups (see the comment a
675          * little later).  And yet, if all the groups are this way, we do
676          * regard the beam as affected, because then we aren't going to enforce
677          * the rule about stems reaching the middle staff line.
678          */
679         /* first set normal (non-CSS) values */
680         css_affects_beam = NO;
681         all_notes_other_staff = NO;
682         if (CSSused == YES) {   /* don't waste time looking if CSS not used */
683                 all_notes_other_staff = YES;
684                 css_affects_beam = css_affects_stemtip(start_p);
685                 for (gs_p = start_p; gs_p != end_p; gs_p = nextsimilar(gs_p)) {
686                         if (NNN(gs_p) != 0) {
687                                 all_notes_other_staff = NO;
688                         }
689                 }
690                 if (all_notes_other_staff == YES) {
691                         css_affects_beam = YES;
692                 }
693         }
694
695         /*
696          * If the beam is not affected by CSS, handle this beamed set on the
697          * first pass only.  If it is affected, handle it on the second
698          * pass only.
699          */
700         if (css_affects_beam != CSSpass) {
701                 return;
702         }
703
704         /*
705          * If the beam is "not affected by CSS", there could still be groups
706          * where all the notes are CSS.  We fake them out here, setting the
707          * BNOTE's RY an octave from the center line.  We need some plausible
708          * value there for finding the beam position.  AY hasn't been used yet,
709          * so use it as a holding area.  We need to restore RY before returning
710          * from this function.
711          */
712         if (CSSused == YES && CSSpass == NO) {
713                 for (gs_p = start_p; gs_p != end_p; gs_p = nextsimilar(gs_p)) {
714                         if (NNN(gs_p) == 0) {
715                                 BNOTE(gs_p).c[AY] = BNOTE(gs_p).c[RY];
716                                 BNOTE(gs_p).c[RY] = 7 * Stepsize *
717                                         ((gs_p->stemdir == UP) ? -1.0 : 1.0);
718                         }
719                 }
720         }
721
722         last_p = 0;     /* prevent useless 'used before set' warnings */
723
724         /* find the last valid group */
725         for (gs_p = start_p; gs_p != end_p; gs_p = nextsimilar(gs_p)) {
726                 last_p = gs_p;
727         }
728
729         /*
730          * If the user specified the stem length on one end (first or last) but
731          * not the other, remember that fact.  In that case we will execute the
732          * normal (both ends unforced) algorithm, but then at the last minute
733          * force the end that was given.
734          */
735         one_end_forced = IS_STEMLEN_KNOWN(start_p->stemlen) !=
736                          IS_STEMLEN_KNOWN(last_p->stemlen);
737
738         /*
739          * If the user specified the stem length for the first and last groups,
740          * simply use these values to define where the beam is, and set all the
741          * stem lengths.
742          */
743         if (IS_STEMLEN_KNOWN(start_p->stemlen) &&
744             IS_STEMLEN_KNOWN(last_p->stemlen)) {
745
746                 /*
747                  * If the first and last groups had stemlen set to zero, force
748                  * all groups to have stemlen zero, and return.  No beam will
749                  * be drawn.
750                  */
751                 if (start_p->stemlen == 0.0 && last_p->stemlen == 0.0) {
752                         for (gs_p = start_p; gs_p != end_p;
753                                         gs_p = nextsimilar(gs_p)) {
754                                 gs_p->stemlen = 0.0;
755                         }
756                         restore_ry(start_p, end_p);
757                         return;
758                 }
759
760                 /* they weren't both zero, so continue on finding the beam */
761                 start_p->stemlen *= Staffscale;
762                 stemshift = getstemshift(start_p);
763                 if (start_p->stemdir == DOWN)
764                         stemshift = -stemshift;
765                 last_p->stemlen *= Staffscale;
766
767                 /* find coords of the ends of the stems on the outer groups */
768                 startx = start_p->c[AX] + stemshift;
769                 endx = last_p->c[AX] + stemshift;
770                 starty = BNOTE(start_p).c[RY] + start_p->stemlen *
771                                 (start_p->stemdir == UP ? 1.0 : -1.0);
772                 endy = BNOTE(last_p).c[RY] + last_p->stemlen *
773                                 (last_p->stemdir == UP ? 1.0 : -1.0);
774
775                 /* find slope and y intercept of line through those points */
776                 b1 = (starty - endy) / (startx - endx);
777                 b0 = starty - b1 * startx;
778
779                 /* loop through all groups, setting stem length */
780                 for (gs_p = start_p; gs_p != end_p; gs_p = nextsimilar(gs_p)) {
781                         x = gs_p->c[AX] + stemshift;    /* X coord of stem */
782
783                         /* first set stemlen to beam's Y coord minus note's */
784                         gs_p->stemlen = (b0 + b1 * x) - BNOTE(gs_p).c[RY];
785
786                         /* if stems are down, reverse it */
787                         if (gs_p->stemdir == DOWN)
788                                 gs_p->stemlen = -(gs_p->stemlen);
789
790                         finalstemadjust(gs_p);
791                 }
792
793                 /* set relative vertical coords of any embedded rests */
794                 embedrest(start_p, last_p, b1, b0);
795
796                 restore_ry(start_p, end_p);
797                 return;
798         }
799
800         /*
801          * If the user forced the beam's angle to some value, find what that is
802          * in terms of slope.  Later we will force this value to be used.  The
803          * 0.001 is to allow for floating point roundoff error.
804          */
805         if (fabs(start_p->beamslope - NOBEAMANGLE) < 0.001) {
806                 slope_forced = NO;
807                 forced_slope = 0.0;     /* not used, keep lint happy */
808         } else {
809                 slope_forced = YES;
810                 forced_slope = tan(start_p->beamslope * PI / 180.0);
811         }
812
813         /*
814          * When both end groups have stemlen zero, we set all groups' stemlens
815          * to zero, and no beam will be drawn.  Above we handled the case
816          * where the user forced both ends to zero.  Here we handle the case
817          * where the ends are defaulting to zero, or one end is defaulting to
818          * zero and the user forced the other one.  But don't do this if the
819          * slope is forced.
820          */
821         if (Defstemsteps == 0.0 && ! slope_forced && ( ! one_end_forced ||
822                         start_p->stemlen == 0.0 || last_p->stemlen == 0.0)) {
823                 for (gs_p = start_p; gs_p != end_p; gs_p = nextsimilar(gs_p)) {
824                         gs_p->stemlen = 0.0;
825                 }
826                 restore_ry(start_p, end_p);
827                 return;
828         }
829
830         /*
831          * Use linear regression to find the best-fit line through the centers
832          * of the notes.  In this function, we will always be concerned with
833          * the X coord of the group as a whole (disregarding any notes that are
834          * on the "wrong" side of the stem) but the Y coord of the note of the
835          * group that's nearest to the beam (thus the BNOTE macro).  The X
836          * coords used are absolute, but the Y coords are relative to the
837          * center line of the staff, since we don't know the absolute Y coords
838          * yet, and it wouldn't affect the result anyway.
839          *
840          * First get sum of x and y coords, to find averages.
841          */
842         sx = sy = 0;
843         num = 0;
844         for (gs_p = start_p; gs_p != end_p; gs_p = nextsimilar(gs_p)) {
845                 sx += gs_p->c[AX];
846                 sy += BNOTE(gs_p).c[RY];
847                 num++;                  /* count number of notes */
848         }
849
850         xbar = sx / num;
851         ybar = sy / num;
852
853         /* accumulate numerator & denominator of regression formula for b1 */
854         top = bottom = 0;
855         for (gs_p = start_p; gs_p != end_p; gs_p = nextsimilar(gs_p)) {
856                 temp = gs_p->c[AX] - xbar;
857                 top += temp * (BNOTE(gs_p).c[RY] - ybar);
858                 bottom += temp * temp;
859         }
860
861         b1 = top / bottom;              /* slope */
862         /*
863          * We could also figure:
864          *      b0 = ybar - b1 * xbar;          y intercept
865          * to get the equation of the regression line:  y = b0 + b1 * x
866          * but we're going to change b0 later anyway.  Now, there are certain
867          * cases where we want to override the slope determined by regression,
868          * so revise b1 if that is the case.
869          */
870
871         /* if first and last notes are equal, force horizontal */
872         if (BNOTE(start_p).stepsup == BNOTE(last_p).stepsup)
873                 b1 = 0.0;
874
875         /* check for more reasons to force the beam horizontal */
876         if (b1 != 0.0 && num >= 3) {
877                 /* get an array of each group's beamside note's stepsup */
878                 MALLOCA(short, steps, num);
879                 for (n = 0, gs_p = start_p; n < num;
880                                 n++, gs_p = nextsimilar(gs_p)) {
881                         steps[n] = BNOTE(gs_p).stepsup;
882                 }
883
884                 /*
885                  * Check for a repeating pattern of notes.  Try every possible
886                  * pattern length <= half as long as set.  If found, force the
887                  * beam horizontal.
888                  */
889                 for (patlen = num / 2; patlen >= 2; patlen--) {
890                         /* must be an integer number of pattern repetitions */
891                         if (num % patlen != 0) {
892                                 continue;       /* groups were left over */
893                         }
894                         /* see if initial pattern repeats perfectly */
895                         match = YES;
896                         for (n = 0; n < patlen && match == YES; n++) {
897                                 for (k = n + patlen; k < num; k += patlen) {
898                                         if (steps[k] != steps[n]) {
899                                                 match = NO;
900                                                 break;
901                                         }
902                                 }
903                         }
904                         /* if all repeats matched, force horizontal & break */
905                         if (match == YES) {
906                                 b1 = 0.0;
907                                 break;
908                         }
909                 }
910
911                 /*
912                  * If still not horizontal, check for the case where all the
913                  * beamside notes are the same except for just the first, or
914                  * just the last, being different and in the direction
915                  * opposite the stemdir.  If so, force horizontal.
916                  */
917                 if (b1 != 0.0) {
918                         /* make sure all the inner groups are the same */
919                         match = YES;
920                         for (n = 2; n < num - 1; n++) {
921                                 if (steps[n] != steps[1]) {
922                                         match = NO;
923                                         break;
924                                 }
925                         }
926                         /* if inner groups same, check the other conditions */
927                         if (match == YES) {
928                                 if (start_p->stemdir == DOWN) {
929                                         if ((steps[0] > steps[1] &&
930                                             steps[num-1] == steps[1]) ||
931                                             (steps[0] == steps[1] &&
932                                             steps[num-1] > steps[1])) {
933                                                 b1 = 0.0;
934                                         }
935                                 } else {        /* UP */
936                                         if ((steps[0] < steps[1] &&
937                                             steps[num-1] == steps[1]) ||
938                                             (steps[0] == steps[1] &&
939                                             steps[num-1] < steps[1])) {
940                                                 b1 = 0.0;
941                                         }
942                                 }
943                         }
944                 }
945                 FREE(steps);
946         }
947
948         /*
949          * Find half the width of a note head; the stems will need to be
950          * shifted by that amount from the center of the notes so that they
951          * will meet the edge of the notes properly.  If the stems are up,
952          * they will be on the right side of (normal) notes, else left.  Set
953          * the X positions for the first and last stems.  (If these are alted
954          * groups, the noteheadchar may not be 4; but this is close enough.)
955          */
956         stemshift = getstemshift(start_p);
957         if (start_p->stemdir == DOWN)
958                 stemshift = -stemshift;
959         startx = start_p->c[AX] + stemshift;    /* first group's stem */
960         endx = last_p->c[AX] + stemshift;       /* last group's stem */
961
962         /*
963          * The original slope derived by linear regression must be adjusted in
964          * certain ways.  First, override it if the user wants that; otherwise
965          * adjust according to the beamslope parameter.
966          */
967         if (slope_forced) {
968                 b1 = forced_slope;
969         } else {
970                 b1 = adjslope(start_p, b1, NO);
971         }
972
973         /*
974          * Calculate a new y intercept (b0).  First pass parallel lines
975          * through each note, and record the maximum and minimum y intercepts
976          * that result.
977          */
978         b0 = BNOTE(start_p).c[RY] - b1 * start_p->c[AX];
979         maxb0 = minb0 = b0;             /* init to value for first note */
980         /* look at rest of them */
981         for (gs_p = nextsimilar(start_p); gs_p != end_p;
982                         gs_p = nextsimilar(gs_p)) {
983                 b0 = BNOTE(gs_p).c[RY] - b1 * gs_p->c[AX];
984                 if (b0 > maxb0)
985                         maxb0 = b0;
986                 else if (b0 < minb0)
987                         minb0 = b0;
988         }
989
990         /*
991          * Find the basictime of the shortest note in the group, considering
992          * also any slashes or alternations on it.  (Except that slash has a
993          * different meaning on grace groups, and doesn't affect their stem
994          * length.)  Then set the default stem length based on that.
995          */
996         shortest = 0;
997         for (gs_p = start_p; gs_p != end_p; gs_p = nextsimilar(gs_p)) {
998                 if (gs_p->basictime >= 8)
999                         bf = drmo(gs_p->basictime) - 2; /* no. of beams/flags*/
1000                 else
1001                         bf = 0;                 /* none on quarter or longer */
1002                 if (gs_p->grpvalue == GV_NORMAL)
1003                         bf += abs(gs_p->slash_alt);/* slashes or alternations */
1004                 /*
1005                  * In certain cases where there are accidentals, we need to
1006                  * artificially increase bf to keep the beams from overlapping
1007                  * with the accidental.
1008                  */
1009                 if (gs_p != start_p && gs_p->stemdir == UP &&
1010                                 gs_p->notelist[0].accidental != '\0' &&
1011                                 gs_p->notelist[0].accidental != 'x' &&
1012                                 b1 > 0 && bf > 1) {
1013                         bf += 3.5 * b1 * (Stepsize / Flagsep) * ((bf > 1) +
1014                                         (gs_p->notelist[0].accidental == 'B'));
1015                 }
1016                 if (bf > shortest)
1017                         shortest = bf;
1018         }
1019         if (allsmall(start_p, last_p) == NO) {
1020                 /* at least one group has a normal size note */
1021                 deflen = Defstemsteps * Stepsize;
1022                 if (shortest > 2)
1023                         deflen += (shortest - 2) * Flagsep;
1024         } else {
1025                 /* all groups have all small notes */
1026                 deflen = Defstemsteps * SM_STEMFACTOR * Stepsize;
1027                 if (shortest > 2)
1028                         deflen += (shortest - 2) * 4.0 * POINT * Staffscale;
1029         }
1030
1031         /*
1032          * The outer edge of the beam should be deflen steps away from the
1033          * average position of the notes, as defined by the linear regression
1034          * line.  But don't allow any note to be closer than a certain number
1035          * of steps less than that, the number as given by the stemshorten parm.
1036          */
1037         shortdist = vvpath(start_p->staffno, start_p->vno, STEMSHORTEN)
1038                         ->stemshorten * Stepsize;
1039         if (start_p->stemdir == UP) {
1040                 if (maxb0 - minb0 > shortdist)
1041                         b0 = maxb0 + deflen - shortdist;
1042                 else
1043                         b0 += deflen;
1044         } else { /* DOWN */
1045                 if (maxb0 - minb0 > shortdist)
1046                         b0 = minb0 - deflen + shortdist;
1047                 else
1048                         b0 -= deflen;
1049         }
1050
1051         /*
1052          * Another adjustment may be needed so that all stems will reach the
1053          * center line of the staff.  (Not to be done for small groups, or when
1054          * all notes in all groups are on the other staff [CSS], or when
1055          * some stemdirs have been forced wrong way despite the other voice, or
1056          * we have alternations and no normal beams, or for voice 3.)
1057          */
1058         starty = b0 + b1 * startx;      /* y coord near left end of beam */
1059         endy = b0 + b1 * endx;          /* y coord near right end of beam */
1060         if (start_p->basictime >= 2 && start_p->grpsize == GS_NORMAL &&
1061                         stemforced(start_p, ogs_p) == NO &&
1062                         start_p->vno != 3 && all_notes_other_staff == NO) {
1063                 if (slope_forced) {
1064                         /* move both ends the same amount to preserve slope */
1065                         if (start_p->stemdir == UP) {
1066                                 if (starty < 0) {
1067                                         endy -= starty;
1068                                         starty = 0;
1069                                 }
1070                                 if (endy < 0) {
1071                                         starty -= endy;
1072                                         endy = 0;
1073                                 }
1074                         } else { /* DOWN */
1075                                 if (starty > 0) {
1076                                         endy -= starty;
1077                                         starty = 0;
1078                                 }
1079                                 if (endy > 0) {
1080                                         starty -= endy;
1081                                         endy = 0;
1082                                 }
1083                         }
1084                 } else {
1085                         /* move just the end(s) that need to be moved */
1086                         if (start_p->stemdir == UP) {
1087                                 if (starty < 0)
1088                                         starty = 0;
1089                                 if (endy < 0)
1090                                         endy = 0;
1091                         } else { /* DOWN */
1092                                 if (starty > 0)
1093                                         starty = 0;
1094                                 if (endy > 0)
1095                                         endy = 0;
1096                         }
1097                 }
1098         }
1099
1100         /*
1101          * If the first and last groups's stems now end at the center line, and
1102          * the beam slope used to be nonzero, force one end to be a step beyond
1103          * the center line, so that the beam will still have some slope to it.
1104          * But don't do this if the user is forcing the beam's slope.
1105          */
1106         if ( ! slope_forced && fabs(starty) < Stdpad &&
1107                                 fabs(endy) < Stdpad && b1 != 0.0) {
1108                 if (start_p->stemdir == UP) {
1109                         if (b1 > 0.0) {
1110                                 endy = Stepsize;
1111                         } else if (b1 < 0.0) {
1112                                 starty = Stepsize;
1113                         }
1114                 } else {        /* DOWN */
1115                         if (b1 > 0.0) {
1116                                 starty = -Stepsize;
1117                         } else if (b1 < 0.0) {
1118                                 endy = -Stepsize;
1119                         }
1120                 }
1121         }
1122
1123         /*
1124          * If y at the ends of the beam differs by less than a step (allowing a
1125          * fudge factor for roundoff error), force the beam horizontal by
1126          * setting one end farther away from the notes.  But don't do it if the
1127          * user is forcing a particular slope.
1128          */
1129         if ( ! slope_forced && fabs(starty - endy) < Stepsize - 0.001) {
1130                 if (start_p->stemdir == UP) {
1131                         if (starty > endy) {
1132                                 endy = starty;
1133                         } else {
1134                                 starty = endy;
1135                         }
1136                 } else {        /* DOWN */
1137                         if (starty < endy) {
1138                                 endy = starty;
1139                         } else {
1140                                 starty = endy;
1141                         }
1142                 }
1143         }
1144
1145         /* recalculate slope and y intercept from (possibly) new endpoints */
1146         b1 = (endy - starty) / (endx - startx);         /* slope */
1147         b0 = starty - b1 * startx;                      /* y intercept */
1148         temp = b0;                      /* remember this value for later */
1149
1150         /* do some additional work for nongrace groups */
1151         if (start_p->grpvalue == GV_NORMAL) {
1152                 /*
1153                  * If this is not an alted pair, there may be embedded grace
1154                  * notes, and we may need to lengthen our stems to avoid them.
1155                  */
1156                 if (start_p->slash_alt >= 0)
1157                         b0 = embedgrace(start_p, b1, b0);
1158
1159                 /* may need to lengthen stems to avoid embedded clefs */
1160                 b0 = embedclef(start_p, b1, b0);
1161
1162                 /* set relative vertical coords of any embedded rests */
1163                 embedrest(start_p, last_p, b1, b0);
1164
1165                 /*
1166                  * If there is another voice, we might need to lengthen our
1167                  * stems so their notes won't run into our beam.  If we had
1168                  * embedded rests, they would also be moved.
1169                  */
1170                 b0 = avoidothervoice(start_p, last_p, b1, b0, ogs_p);
1171
1172                 /* update these by the amount the y intercept changed */
1173                 starty += temp - b0;
1174                 endy += temp - b0;
1175         }
1176
1177         restore_ry(start_p, end_p);
1178
1179         /*
1180          * If one end's stem len was forced but not the other, now is the time
1181          * to apply that forcing.  So in effect, we have taken the beam as
1182          * determined by the normal algorithm and now we change the vertical
1183          * coord of this end.  If the slope was also forced, move the other
1184          * end by the same amount so that the slope won't change.
1185          */
1186         if (one_end_forced) {
1187                 if (IS_STEMLEN_KNOWN(start_p->stemlen)) {
1188                         start_p->stemlen *= Staffscale;
1189                         temp = starty;
1190                         starty = BNOTE(start_p).c[RY] + start_p->stemlen *
1191                                         (start_p->stemdir == UP ? 1.0 : -1.0);
1192                         if (slope_forced) {
1193                                 endy += starty - temp;
1194                         }
1195                 } else {
1196                         last_p->stemlen *= Staffscale;
1197                         temp = endy;
1198                         endy = BNOTE(last_p).c[RY] + last_p->stemlen *
1199                                         (last_p->stemdir == UP ? 1.0 : -1.0);
1200                         if (slope_forced) {
1201                                 starty += endy - temp;
1202                         }
1203                 }
1204
1205                 /* recalculate */
1206                 b1 = (endy - starty) / (endx - startx); /* slope */
1207                 b0 = starty - b1 * startx;              /* y intercept */
1208
1209                 /*
1210                  * Re-do embedded rests now that things have moved.  As for the
1211                  * other adjustments above, we can't re-do them because they
1212                  * may force stem lengths to change.  If things collide, too
1213                  * bad, the user forced the one stem length.  It might be
1214                  * possible to avoid the collision by moving the other end,
1215                  * but likely not, and it's too late now anyhow.
1216                  */
1217                 embedrest(start_p, last_p, b1, b0);
1218         }
1219
1220         /*
1221          * At this point we know where to put the main beam (the one needed for
1222          * eighth notes).  Figure out and set the correct stem lengths for all
1223          * of these beamed groups.
1224          */
1225         for (gs_p = start_p; gs_p != end_p; gs_p = nextsimilar(gs_p)) {
1226                 x = gs_p->c[AX] + stemshift;    /* X coord of stem */
1227
1228                 /* first set stemlen to beam's Y coord minus note's */
1229                 gs_p->stemlen = (b0 + b1 * x) - BNOTE(gs_p).c[RY];
1230
1231                 /* if stems down, reverse stemlen, should make it positive */
1232                 if (gs_p->stemdir == DOWN) {
1233                         gs_p->stemlen = -(gs_p->stemlen);
1234                 }
1235                 /* but if negative length, error */
1236                 if (gs_p->stemlen < 0) {
1237                         l_ufatal(gs_p->inputfile, gs_p->inputlineno,
1238                                         "stem length was forced negative");
1239                 }
1240
1241                 finalstemadjust(gs_p);
1242         }
1243 }
1244 \f
1245 /*
1246  * Name:        restore_ry()
1247  *
1248  * Abstract:    Restore RY coordinates if need be.
1249  *
1250  * Returns:     void
1251  *
1252  * Description: This function undoes what the code near the start of setbeam()
1253  *              did.  But it doesn't have to set AY back, because it is garbage
1254  *              and will be overwritten later anyway.
1255  */
1256
1257 static void
1258 restore_ry(start_p, end_p)
1259
1260 struct GRPSYL *start_p;         /* first in beamed set */
1261 struct GRPSYL *end_p;           /* after last in beamed set */
1262
1263 {
1264         struct GRPSYL *gs_p;    /* loop through the groups in the beamed set */
1265
1266
1267         if (CSSused == YES && CSSpass == NO) {
1268                 for (gs_p = start_p; gs_p != end_p; gs_p = nextsimilar(gs_p)) {
1269                         if (NNN(gs_p) == 0) {
1270                                 BNOTE(gs_p).c[RY] = BNOTE(gs_p).c[AY];
1271                         }
1272                 }
1273         }
1274 }
1275 \f
1276 /*
1277  * Name:        embedgrace()
1278  *
1279  * Abstract:    Change the Y intercept if necessary for embedded grace groups.
1280  *
1281  * Returns:     new y intercept value (may be no change)
1282  *
1283  * Description: When grace groups are embedded inside a set of nongrace groups,
1284  *              the beam(s) for the nongrace may have to be put farther away
1285  *              from their note heads, so that these beams won't collide with
1286  *              the grace groups.  This function returns the new Y intercept
1287  *              for the equation of the nongraces' main beam, which accom-
1288  *              plishes this.  When there aren't any embedded grace groups,
1289  *              or they are in certain positions, this Y intercept will be the
1290  *              same as the old Y intercept.
1291  */
1292
1293 static double
1294 embedgrace(start_p, b1, b0)
1295
1296 struct GRPSYL *start_p; /* first group in nongrace beamed set */
1297 double b1;              /* slope */
1298 double b0;              /* y intercept */
1299
1300 {
1301         struct GRPSYL *gs_p;    /* point to grace group being looked at */
1302         struct GRPSYL *prev_p;  /* point to nongrace group preceding gs_p */
1303         struct GRPSYL *next_p;  /* point to nongrace group following gs_p */
1304         float beamthick;        /* total thickness of beams and space between*/
1305         float ycross;           /* where grace stem would hit nongrace beam */
1306
1307
1308         /*
1309          * Loop through all the grace groups that are embedded somewhere
1310          * between the first and last groups of this nongrace beamed set.
1311          * If their stems point the opposite way, there is no problem.  But
1312          * if not, we may need to move the main beam(s) out of the way.
1313          */
1314         for (gs_p = start_p; gs_p->grpvalue == GV_ZERO ||
1315                                 gs_p->beamloc != ENDITEM; gs_p = gs_p->next) {
1316                 if (gs_p->grpvalue == GV_NORMAL)
1317                         continue;       /* ignore nongrace groups */
1318
1319                 /*
1320                  * Find the preceding and following nongrace group.  Whichever
1321                  * has the least (slowest) basictime, that determines how many
1322                  * full beams will connect those two groups.  (You take log2 of
1323                  * it and subtract 2.)
1324                  */
1325                 prev_p = prevnongrace(gs_p);
1326                 next_p = nextnongrace(gs_p);
1327
1328                 /* thickness of relevant beams at right side of grace */
1329                 beamthick = beamoff(next_p, PB_LEFT, gs_p->c[AE], start_p);
1330
1331                 /*
1332                  * Find the AX and RY coords of the end of the grace group
1333                  * stem that is nearest the nongrace beam(s).  Then, if this
1334                  * point would run into or beyond the nongrace beam(s), change
1335                  * the Y intercept (b0) so that it won't.
1336                  */
1337                 ycross = b1 * gs_p->c[AE] + b0;
1338                 if (start_p->stemdir == UP) {
1339                         if (ycross - beamthick < gs_p->c[RN])
1340                                 b0 += gs_p->c[RN] - (ycross - beamthick);
1341                 } else {        /* stemdir == DOWN */
1342                         if (ycross + beamthick > gs_p->c[RS])
1343                                 b0 -= (ycross + beamthick) - gs_p->c[RS];
1344                 }
1345
1346                 /* thickness of relevant beams at left side of grace */
1347                 beamthick = beamoff(prev_p, PB_RIGHT, gs_p->c[AW], start_p);
1348
1349                 ycross = b1 * gs_p->c[AW] + b0;
1350                 if (start_p->stemdir == UP) {
1351                         if (ycross - beamthick < gs_p->c[RN])
1352                                 b0 += gs_p->c[RN] - (ycross - beamthick);
1353                 } else {        /* stemdir == DOWN */
1354                         if (ycross + beamthick > gs_p->c[RS])
1355                                 b0 -= (ycross + beamthick) - gs_p->c[RS];
1356                 }
1357         }
1358
1359         return (b0);    /* new (possibly changed) Y intercept */
1360 }
1361 \f
1362 /*
1363  * Name:        embedclef()
1364  *
1365  * Abstract:    Change the Y intercept if necessary for embedded clefs.
1366  *
1367  * Returns:     new y intercept value (may be no change)
1368  *
1369  * Description: When clef changes occur before groups in a beamed set, the
1370  *              beam(s) for the set may have to be put farther away from their
1371  *              note heads, so that these beams won't collide with the clefs.
1372  *              This function returns the new Y intercept for the equation of
1373  *              the nongraces' main beam, which accomplishes this.  When there
1374  *              aren't any embedded clefs, or they are in certain positions,
1375  *              this Y intercept will be the same as the old Y intercept.
1376  */
1377
1378 static double
1379 embedclef(start_p, b1, b0)
1380
1381 struct GRPSYL *start_p; /* first group in nongrace beamed set */
1382 double b1;              /* slope */
1383 double b0;              /* y intercept */
1384
1385 {
1386         struct GRPSYL *gs_p;    /* point to group being looked at */
1387         struct GRPSYL *pbgs_p;  /* group whose partial beams may impact us */
1388         float north, south;     /* top and bottom edge of a clef */
1389         float horizontal;       /* left or right edge of a clef */
1390         float beamthick;        /* total thickness of beams and space between*/
1391         float ycross;           /* where grace stem would hit nongrace beam */
1392
1393
1394         /*
1395          * Loop through all the groups between the first and last groups of
1396          * this nongrace beamed set, including the last but not the first, and
1397          * including any embedded graces.  If any are preceded by a clef, we
1398          * may need to move the beam(s) out of the way.
1399          */
1400         for (gs_p = start_p->next; gs_p != 0 && ! (gs_p->prev->grpvalue ==
1401                         GV_NORMAL && gs_p->prev->beamloc == ENDITEM);
1402                         gs_p = gs_p->next) {
1403
1404                 if (gs_p->clef == NOCLEF) {
1405                         continue;       /* ignore groups with no clef */
1406                 }
1407
1408                 /* find the vertical edges of the clef */
1409                 (void)clefvert(gs_p->clef, YES, &north, &south);
1410                 north *= Staffscale;
1411                 south *= Staffscale;
1412
1413                 /*
1414                  * Make sure the right side of the clef doesn't collide with
1415                  * the beams.
1416                  */
1417                 /* find right side of the clef */
1418                 horizontal = gs_p->c[AW] - CLEFPAD * Staffscale;
1419
1420                 /* group whose partial beams we need to worry about */
1421                 pbgs_p = gs_p->grpvalue == GV_ZERO ? nextnongrace(gs_p) : gs_p;
1422
1423                 /* thickness of relevant beams at right side of clef */
1424                 beamthick = beamoff(pbgs_p, PB_LEFT, horizontal, start_p);
1425
1426                 /* Find RY where right edge of clef would hit the main beam. If
1427                  * that edge of clef would hit any beam, change Y intercept. */
1428                 ycross = b1 * horizontal + b0;
1429                 if (start_p->stemdir == UP) {
1430                         if (ycross - beamthick < north) {
1431                                 b0 += north - (ycross - beamthick);
1432                         }
1433                 } else {        /* stemdir == DOWN */
1434                         if (ycross + beamthick > south) {
1435                                 b0 -= (ycross + beamthick) - south;
1436                         }
1437                 }
1438
1439                 /*
1440                  * Make sure the left side of the clef doesn't collide with
1441                  * the beams.
1442                  */
1443                 /* find left side of the clef */
1444                 horizontal -= clefwidth(gs_p->clef, YES) * Staffscale;
1445
1446                 /* group whose partial beams we need to worry about */
1447                 pbgs_p = prevnongrace(gs_p);
1448
1449                 /* thickness of relevant beams at left side of clef */
1450                 beamthick = beamoff(pbgs_p, PB_RIGHT, horizontal, start_p);
1451
1452                 /* Find RY where left edge of clef would hit main beam.  If
1453                  * that edge of clef would hit any beam, change Y intercept. */
1454                 ycross = b1 * horizontal + b0;
1455                 if (start_p->stemdir == UP) {
1456                         if (ycross - beamthick < north) {
1457                                 b0 += north - (ycross - beamthick);
1458                         }
1459                 } else {        /* stemdir == DOWN */
1460                         if (ycross + beamthick > south) {
1461                                 b0 -= (ycross + beamthick) - south;
1462                         }
1463                 }
1464         }
1465
1466         return (b0);    /* new (possibly changed) Y intercept */
1467 }
1468 \f
1469 /*
1470  * Name:        beamoff()
1471  *
1472  * Abstract:    On one side of group, get height of beams and spaces between.
1473  *
1474  * Returns:     height in inches
1475  *
1476  * Description: This function is called with a nongrace group in beamed set, to
1477  *              find out how many beams it has on one side of it and how high
1478  *              they are.  If the group is the first or last in the set, the
1479  *              side must be the interior side.  Partial beams are also figured
1480  *              in, if they might extend far enough to reach the "boundary"
1481  *              coordinate.
1482  */
1483
1484 static double
1485 beamoff(gs_p, side, boundary, start_p)
1486
1487 struct GRPSYL *gs_p;    /* group we are concerned with */
1488 int side;               /* which side of the group, PB_LEFT or PB_RIGHT */
1489 double boundary;        /* X coord of edge of thing that must not collide */
1490 struct GRPSYL *start_p; /* first group in nongrace beamed set */
1491
1492 {
1493         struct GRPSYL *ogs_p;   /* nongrace group on "side" side of gs_p */
1494         struct GRPSYL *o2gs_p;  /* nongrace group on other side of gs_p */
1495         int beams;              /* number of beams for figuring collision */
1496         int minbasic;           /* minimum (longest) basictime */
1497
1498
1499         /*
1500          * If it's the left side of this group we're worried about, set ogs_p
1501          * to the previous nongrace, and o2gs_p to the next.  If right, do the
1502          * opposite.
1503          */
1504         if (side == PB_LEFT) {
1505                 ogs_p = prevnongrace(gs_p);
1506                 o2gs_p = nextnongrace(gs_p);
1507         } else {
1508                 ogs_p = nextnongrace(gs_p);
1509                 o2gs_p = prevnongrace(gs_p);
1510         }
1511
1512         /*
1513          * Whichever of the two groups {this group, the group on the side
1514          * that we're worried about} has the least (slowest) basictime, that
1515          * determines how many full beams will connect those two groups.  (You
1516          * take log2 of it and subtract 2.)
1517          */
1518         minbasic = MIN(gs_p->basictime, ogs_p->basictime);
1519         if (minbasic >= 8) {
1520                 beams = drmo(MIN(gs_p->basictime, ogs_p->basictime)) - 2;
1521         } else {
1522                 beams = 0;      /* must be an alternation */
1523         }
1524
1525         /* add the number of alternation beams, if any */
1526         if (gs_p->slash_alt < 0) {
1527                 beams -= gs_p->slash_alt;
1528         }
1529
1530         /*
1531          * If our group needs more beams than the group on the requested side,
1532          * and the stem is in the direction where partial beams would stick out
1533          * beyond our GRPSYL boundary and the partial beams are long enough to
1534          * possibly collide with the thing we're trying to avoid . . .
1535          */
1536         if (gs_p->basictime > ogs_p->basictime &&
1537                         (side == PB_LEFT && gs_p->stemdir == DOWN &&
1538                                 gs_p->c[AW] - 5.0 * Stepsize < boundary ||
1539                         side == PB_RIGHT && gs_p->stemdir == UP &&
1540                                 gs_p->c[AE] + 5.0 * Stepsize > boundary)) {
1541                 /*
1542                  * If we are the start or end of this beamed set, or we need
1543                  * more beams than the group on the other side . . .
1544                  */
1545                 if (gs_p->beamloc == STARTITEM || gs_p->beamloc == ENDITEM ||
1546                                 gs_p->basictime > o2gs_p->basictime) {
1547                         /*
1548                          * We have partial beam(s); if on the side that matters
1549                          * to us, reset the number of beams to include partials.
1550                          */
1551                         if (pbeamside(gs_p, start_p) == side) {
1552                                 beams = drmo(gs_p->basictime) - 2;
1553                         }
1554                 }
1555         }
1556
1557         /*
1558          * To get total beam thickness, multiply the size of one beam by the
1559          * number of beams.  Also add in a small fudge factor.
1560          */
1561         return (Flagsep * beams + Stepsize / 2.0);
1562 }
1563 \f
1564 /*
1565  * Name:        embedrest()
1566  *
1567  * Abstract:    Set relative vertical coords of rests embedded in beamed sets.
1568  *
1569  * Returns:     void
1570  *
1571  * Description: Rests' vertical coords were set in restsyl.c.  But when a rest
1572  *              is embedded in a beamed set, its coords may have to be changed
1573  *              now so that it fits well.
1574  */
1575
1576 static void
1577 embedrest(start_p, last_p, b1, b0)
1578
1579 struct GRPSYL *start_p; /* first group in nongrace beamed set */
1580 struct GRPSYL *last_p;  /* last group in nongrace beamed set */
1581 double b1;              /* slope */
1582 double b0;              /* y intercept */
1583
1584 {
1585         struct GRPSYL *gs_p;    /* point to group in the set */
1586         struct GRPSYL *gp_p, *gpp_p; /* prev nongrace note, and prev to that */
1587         struct GRPSYL *gn_p, *gnn_p; /* next nongrace note, and next to that */
1588         int bp, bn;             /* beams on gp_p and gn_p */
1589         int partial;            /* partial beams in our way */
1590         char rchar;             /* char for the rest */
1591         int size;               /* font size */
1592         float asc, des;         /* ascent and descent of a rest */
1593         float beamthick;        /* total thickness of beams and space between*/
1594         float ycross;           /* where rest would hit beam */
1595         int beams;              /* number of beams joining two groups */
1596
1597
1598         /*
1599          * Loop through the interior groups of this set, setting relative
1600          * vertical coords of rest groups.  (Outer groups are never rests.)
1601          */
1602         for (gs_p = start_p->next; gs_p != last_p; gs_p = gs_p->next) {
1603
1604                 /* skip nonrests */
1605                 if (gs_p->grpcont != GC_REST)
1606                         continue;
1607
1608                 /* skip cases where the user is forcing the coords */
1609                 if (gs_p->restdist != NORESTDIST)
1610                         continue;
1611
1612                 rchar = restchar(gs_p->basictime);
1613                 size = (gs_p->grpsize == GS_NORMAL ? DFLT_SIZE : SMALLSIZE);
1614                 asc = ascent(FONT_MUSIC, size, rchar) * Staffscale;
1615                 des = descent(FONT_MUSIC, size, rchar) * Staffscale;
1616
1617
1618                 /* find prev nongrace note group; will be in this beamed set */
1619                 for (gp_p = gs_p->prev; gp_p->grpcont != GC_NOTES ||
1620                                 gp_p->grpvalue == GV_ZERO; gp_p = gp_p->prev)
1621                         ;
1622
1623                 /* find prev nongrace note group to that, if any */
1624                 for (gpp_p = gp_p->prev; gpp_p != 0 && (gpp_p->grpcont !=
1625                                 GC_NOTES || gpp_p->grpvalue == GV_ZERO);
1626                                 gpp_p= gpp_p->prev)
1627                         ;
1628                 /* but if it's not in this beamed set, forget it */
1629                 if (gpp_p != 0 && gpp_p->beamloc != INITEM &&
1630                                   gpp_p->beamloc != STARTITEM)
1631                         gpp_p = 0;
1632
1633
1634                 /* find next nongrace note group; will be in this beamed set */
1635                 for (gn_p = gs_p->next; gn_p->grpcont != GC_NOTES ||
1636                                 gn_p->grpvalue == GV_ZERO; gn_p = gn_p->next)
1637                         ;
1638
1639                 /* find next nongrace note group to that, if any */
1640                 for (gnn_p = gn_p->next; gnn_p != 0 && (gnn_p->grpcont !=
1641                                 GC_NOTES || gnn_p->grpvalue == GV_ZERO);
1642                                 gnn_p= gnn_p->next)
1643                         ;
1644                 /* but if it's not in this beamed set, forget it */
1645                 if (gnn_p != 0 && gnn_p->beamloc != INITEM &&
1646                                   gnn_p->beamloc != ENDITEM)
1647                         gnn_p = 0;
1648
1649
1650                 /* get number of beams needed by prev and next */
1651                 bp = numbeams(gp_p->basictime);
1652                 bn = numbeams(gn_p->basictime);
1653
1654                 partial = 0;    /* init to no partial beams */
1655
1656                 /*
1657                  * If the group just before our rest is notes, and this beamed
1658                  * set's stems are up, and the prev note needs more beams than
1659                  * the next note, we may have to deal with partial beams.
1660                  */
1661                 if (gs_p->prev->grpcont == GC_NOTES && start_p->stemdir == UP
1662                                 && bp > bn) {
1663                         if (gpp_p == 0) {
1664                                 /* definitely partial beams on this side */
1665                                 partial = bp - bn;
1666                         } else {
1667                                 /* maybe partial beams on this side */
1668                                 if (numbeams(gpp_p->basictime) < bp &&
1669                                 pbeamside(gp_p, start_p) == PB_RIGHT)
1670                                         partial = bp - bn;
1671                         }
1672                         /* but if far enough away horizontally, we can ignore */
1673                         if (gs_p->c[AW] - gp_p->c[AE] > 1.5 * Stepsize)
1674                                 partial = 0;
1675                 }
1676
1677                 /*
1678                  * If the group just after our rest is notes, and this beamed
1679                  * set's stems are down, and the next note needs more beams than
1680                  * the prev note, we may have to deal with partial beams.  If
1681                  * the next group is grace, we might fall into this block, but
1682                  * that's okay; the next nongrace (gn_p) will be far enough
1683                  * away that partial will (correctly) be forced back to 0.
1684                  */
1685                 if (gs_p->next->grpcont == GC_NOTES && start_p->stemdir == DOWN
1686                                 && bn > bp) {
1687                         if (gnn_p == 0) {
1688                                 /* definitely partial beams on this side */
1689                                 partial = bn - bp;
1690                         } else {
1691                                 /* maybe partial beams on this side */
1692                                 if (numbeams(gnn_p->basictime) < bn &&
1693                                 pbeamside(gn_p, start_p) == PB_LEFT)
1694                                         partial = bn - bp;
1695                         }
1696                         /* but if far enough away horizontally, we can ignore */
1697                         if (gn_p->c[AW] - gs_p->c[AE] > 1.5 * Stepsize)
1698                                 partial = 0;
1699                 }
1700
1701                 /* full beams joining prev and next, plus relevant partials */
1702                 beams = MIN(bp, bn) + partial;
1703
1704                 /*
1705                  * To get total beam thickness, multiply the size of one beam
1706                  * by the number of beams.
1707                  */
1708                 beamthick = Flagsep * beams;
1709
1710                 /* find where outer beam hits our rest's X coord */
1711                 ycross = b1 * gs_p->c[AX] + b0;
1712
1713                 /* find vertical coord, quantizing the results */
1714                 if (start_p->stemdir == UP) {
1715                         gs_p->c[RY] = nearestline(ycross - beamthick -
1716                                         asc - Stepsize);
1717                 } else {        /* stemdir == DOWN */
1718                         gs_p->c[RY] = nearestline(ycross + beamthick +
1719                                         des + Stepsize);
1720                 }
1721
1722                 gs_p->c[RN] = gs_p->c[RY] + asc;
1723                 gs_p->c[RS] = gs_p->c[RY] - des;
1724         }
1725 }
1726 \f
1727 /*
1728  * Name:        avoidothervoice()
1729  *
1730  * Abstract:    Change the Y intercept if necessary to avoid the other voice.
1731  *
1732  * Returns:     new y intercept value (may be no change)
1733  *
1734  * Description: When there is another voice, its groups might collide with our
1735  *              voice's beams, unless we lengthen our groups' stems.  This
1736  *              function returns the new Y intercept for the equation of the
1737  *              our voice's main beam, which accomplishes this.  When there is
1738  *              no other voice, or its groups don't interfere with our beam,
1739  *              this Y intercept will be the same as the old Y intercept.
1740  *              When it changes, embedded rests' coords need to be changed too.
1741  */
1742
1743 static double
1744 avoidothervoice(start_p, last_p, b1, b0, ogs_p)
1745
1746 struct GRPSYL *start_p; /* first group in nongrace beamed set */
1747 struct GRPSYL *last_p;  /* last group in nongrace beamed set */
1748 double b1;              /* slope */
1749 double b0;              /* y intercept */
1750 struct GRPSYL *ogs_p;   /* first group in the other voice */
1751
1752 {
1753         struct GRPSYL *prev_p;  /* point to nongrace group preceding gs_p */
1754         struct GRPSYL *prev2_p; /* point to nongrace group before that one */
1755         struct GRPSYL *next_p;  /* point to nongrace group following gs_p */
1756         struct GRPSYL *next2_p; /* point to nongrace group after that one */
1757         struct GRPSYL *gs_p;    /* point to group being looked at */
1758         float beamthick;        /* total thickness of beams and space between*/
1759         float ycross;           /* where grace stem would hit nongrace beam */
1760         float fary;             /* farthest y coord of other voice's group */
1761         int beams;              /* number of beams joining two nongrace groups*/
1762         float thismove;         /* how far one item requires the beam to move*/
1763         float move;             /* distance to move intercept */
1764
1765
1766         move = 0.0;             /* init to no move */
1767
1768         /*
1769          * Loop through all the groups in the other voice.  (If there is no
1770          * other voice, this loop will execute zero times.)  If any of its
1771          * groups land on or beyond our beam, move our beam farther away so
1772          * they don't.
1773          */
1774         for (gs_p = ogs_p; gs_p != 0; gs_p = gs_p->next) {
1775
1776                 /* spaces and rests can't interfere with anything */
1777                 if (gs_p->grpcont != GC_NOTES)
1778                         continue;
1779
1780                 /* if this group is outside our beamed set, ignore it */
1781                 if (gs_p->c[AX] <= start_p->c[AX] ||
1782                     gs_p->c[AX] >=  last_p->c[AX])
1783                         continue;
1784
1785                 /*
1786                  * Find which groups in our set immediately preceed and follow
1787                  * the other voice's group.  These will be prev_p and next_p.
1788                  */
1789                 for (prev_p = next_p = start_p;
1790                      next_p->c[AX] < gs_p->c[AX];
1791                      prev_p = next_p, next_p = nextnongrace(next_p))
1792                         ;
1793
1794                 /*
1795                  * If next_p is lined up with gs_p, and is a note group, that
1796                  * means these groups were "compatible" (see setgrps.c), and so
1797                  * there can be no way that we would have to move our beam.
1798                  * But if next_p is a rest, handle the situation and continue.
1799                  */
1800                 if (next_p->c[AX] == gs_p->c[AX]) {
1801                         if (next_p->grpcont == GC_NOTES)
1802                                 continue;       /* compatible, no problem */
1803
1804                         /*
1805                          * Find the AX and RY coords of the outer edge of the
1806                          * outer note of the other voice's group that is the
1807                          * farthest in the direction of our beam.  Then, if
1808                          * this point would run into or beyond the rest, find
1809                          * how far to move the Y intercept (b0) so that it
1810                          * won't.  Remember the farthest move needed.
1811                          */
1812                         if (start_p->stemdir == UP) {
1813                                 fary = gs_p->notelist[0].c[RN] + Stdpad;
1814                                 if (next_p->c[RS] < fary) {
1815                                         thismove = fary - next_p->c[RS];
1816                                         move = MAX(move, thismove);
1817                                 }
1818                         } else { /* stemdir == DOWN */
1819                                 fary = gs_p->notelist[ gs_p->nnotes-1 ].c[RS]
1820                                                 - Stdpad;
1821                                 if (next_p->c[RN] > fary) {
1822                                         thismove = fary - next_p->c[RN];
1823                                         move = MIN(move, thismove);
1824                                 }
1825                         }
1826
1827                         continue;
1828                 }
1829
1830                 /*
1831                  * Find which of prev_p and next_p has the least (slowest)
1832                  * basictime.  That determines how many full beams will connect
1833                  * those two groups.  (You take log2 of it and subtract 2.)
1834                  * Then add in any alternation beams.
1835                  */
1836                 if (prev_p->basictime >= 8)
1837                         beams = drmo(MIN(prev_p->basictime, next_p->basictime))
1838                                         - 2;
1839                 else
1840                         beams = 0;
1841
1842                 if (prev_p->slash_alt < 0)
1843                         beams -= prev_p->slash_alt;
1844
1845                 /*
1846                  * Find out if there are partial beams on the left side of the
1847                  * following group or right side of the preceding group.  If
1848                  * so, that group's basictime may determine the total number of
1849                  * beams that could interfere with our group, if it's close
1850                  * enough.
1851                  */
1852                 if (prev_p->basictime < next_p->basictime && next_p->stemdir ==
1853                     DOWN && next_p->c[AX] - gs_p->c[AX] < 5 * Stepsize) {
1854
1855                         /* find nongrace group after "next", if one exists */
1856                         next2_p = nextnongrace(next_p);
1857
1858                         /* if "next" group has partial beams . . . */
1859                         if (next2_p == 0 || next_p->beamloc == ENDITEM ||
1860                                 next_p->basictime > next2_p->basictime) {
1861
1862                                 /* if on its left side, reset total beams */
1863                                 if (pbeamside(next_p, start_p) == PB_LEFT)
1864                                         beams = drmo(next_p->basictime) - 2;
1865                         }
1866                 } else if (prev_p->basictime > next_p->basictime && prev_p->
1867                 stemdir == UP && gs_p->c[AX] - prev_p->c[AX] < 5 * Stepsize) {
1868
1869                         /* find nongrace group before "prev", if one exists */
1870                         prev2_p = prevnongrace(prev_p);
1871
1872                         /* if "prev" group has partial beams . . . */
1873                         if (prev2_p == 0 || prev_p->beamloc == STARTITEM ||
1874                                 prev_p->basictime > prev2_p->basictime) {
1875
1876                                 /* if on its right side, reset total beams */
1877                                 if (pbeamside(prev_p, start_p) == PB_RIGHT)
1878                                         beams = drmo(prev_p->basictime) - 2;
1879                         }
1880                 }
1881
1882                 beamthick = Flagsep * beams + Stepsize;
1883
1884                 /*
1885                  * Find the AX and RY coords of the outer edge of the outer
1886                  * note of the other voice's group that is the farthest in the
1887                  * direction of our beam.  Then, if this point would run into
1888                  * or beyond the nongrace beam(s), find how much the Y
1889                  * intercept (b0) would have to move to avoid the collision.
1890                  * Remember the farthest move found so far.
1891                  */
1892                 ycross = b1 * gs_p->c[AX] + b0;
1893                 if (start_p->stemdir == UP) {
1894
1895                         fary = gs_p->notelist[0].c[RN] + Stdpad;
1896                         if (ycross - beamthick < fary) {
1897                                 thismove = fary - (ycross - beamthick);
1898                                 move = MAX(move, thismove);
1899                         }
1900
1901                 } else { /* stemdir == DOWN */
1902
1903                         fary = gs_p->notelist[ gs_p->nnotes-1 ].c[RS] - Stdpad;
1904                         if (ycross + beamthick > fary) {
1905                                 thismove = fary - (ycross + beamthick);
1906                                 move = MIN(move, thismove);
1907                         }
1908                 }
1909         }
1910
1911         if (move == 0.0)
1912                 return (b0);            /* no change; return old intercept */
1913
1914         /*
1915          * If our beamed set has any embedded rests, we want to move the rests
1916          * too.  We really only have to move rests that the other voice is
1917          * bumping into, but it will probably look better to move them all.
1918          * We need to move everything by a multiple of 2 stepsizes, since rests
1919          * should be positioned that way.
1920          */
1921         for (gs_p = start_p->next; gs_p != last_p; gs_p = gs_p->next) {
1922                 /* break out if we find a rest */
1923                 if (gs_p->grpcont == GC_REST)
1924                         break;
1925         }
1926         if (gs_p != last_p) {
1927                 /*
1928                  * We found a rest.  Round the amount the intercept moved up to
1929                  * a multiple of 2 stepsizes.
1930                  */
1931                 move = (move < 0.0 ? -1.0 : 1.0) * 2.0 * Stepsize *
1932                         ((int)(fabs(move) / (2.0 * Stepsize)) + 1);
1933
1934                 /* move every embedded rest by this amount */
1935                 for (gs_p = start_p->next; gs_p != last_p; gs_p = gs_p->next) {
1936                         if (gs_p->grpcont == GC_REST) {
1937                                 gs_p->c[RN] += move;
1938                                 gs_p->c[RY] += move;
1939                                 gs_p->c[RS] += move;
1940                         }
1941                 }
1942         }
1943
1944         return (b0 + move);     /* new Y intercept */
1945 }
1946 \f
1947 /*
1948  * Name:        setgroupvert()
1949  *
1950  * Abstract:    Set RN and RS for each group of given type in a linked list.
1951  *
1952  * Returns:     void
1953  *
1954  * Description: This function loops through the linked list of groups for one
1955  *              voice for one measure.  It handles either grace groups or non-
1956  *              grace groups, whichever it is told to do.  It sets the RN and
1957  *              RS for the groups.
1958  */
1959
1960 static void
1961 setgroupvert(grpvalue, firstgs_p, ogs_p)
1962
1963 int grpvalue;                   /* should we do grace groups or normal groups?*/
1964 struct GRPSYL *firstgs_p;       /* point to first group in a linked list */
1965 struct GRPSYL *ogs_p;           /* point to first group in other linked list */
1966
1967 {
1968         struct GRPSYL *gs_p;    /* point along groups in a linked list */
1969         float outstem;  /* the part of the stemlen outside notes of group */
1970         float stemtip;  /* coord of the end of the stem */
1971         float old;              /* old group boundary */
1972         float delta;            /* change in group boundary */
1973
1974
1975         debug(32, "setgroupvert file=%s line=%d grpvalue=%d",
1976                         firstgs_p->inputfile, firstgs_p->inputlineno, grpvalue);
1977         /*
1978          * Loop through every group, skipping rests, spaces, and groups of the
1979          * wrong type (grace vs. nongrace), setting the relative vertical
1980          * coordinates.
1981          */
1982         for (gs_p = firstgs_p; gs_p != 0; gs_p = gs_p->next) {
1983                 if (gs_p->grpcont != GC_NOTES)
1984                         continue;
1985                 if (gs_p->grpvalue != grpvalue)
1986                         continue;
1987
1988                 /*
1989                  * Back in setnotes.c, we set RY to 0, the center line of the
1990                  * staff.  N was set to the top of the highest note, plus
1991                  * padding, excluding any CSS notes.  S is the analogous thing,
1992                  * below.  But if all notes are CSS, N and S were set to 0.
1993                  */
1994
1995                 /*
1996                  * Now we want to set the stemlen, as well as we can.  For
1997                  * groups whose step tips are not affected by CSS, we do it in
1998                  * the non-CSS pass; otherwise we do it in the CSS pass.
1999                  */
2000                 if (css_affects_stemtip(gs_p) == CSSpass) {
2001
2002                         /*
2003                          * If the group has a stem or pseudostem, we do this
2004                          * work.  Extend the appropriate group boundary to
2005                          * reach to the end of the stem.  Do this for all
2006                          * groups with real stems or pseudostems, excluding
2007                          * cross staff beaming (where we don't know yet how
2008                          * long the stems will be and we don't want to include
2009                          * them in the group boundary anyway, since it would
2010                          * prevent stem overlapping that we want).  That means
2011                          * half notes or shorter (excluding grace quarter
2012                          * notes), or anything with slash/alternations.
2013                          */
2014                         if (gs_p->beamto == CS_SAME &&
2015                            (gs_p->basictime >= 2 || gs_p->slash_alt != 0) &&
2016                             gs_p->stemlen != 0.0) {
2017
2018                                 outstem = gs_p->stemlen
2019                                         - (gs_p->notelist[0].c[RY]
2020                                         - gs_p->notelist[gs_p->nnotes-1].c[RY]);
2021                                 /*
2022                                  * In the CSS pass we also have to adjust the
2023                                  * absolute coords, by the same amount as the
2024                                  * relative, since those have been set by now.
2025                                  */
2026                                 if (gs_p->stemdir == UP) {
2027                                         stemtip = gs_p->notelist[0].c[RY]
2028                                                 + outstem;
2029                                         old = gs_p->c[RN];
2030                                         gs_p->c[RN] = MAX(stemtip, gs_p->c[RN])
2031                                                 + Stdpad;
2032                                         if (CSSpass == YES) {
2033                                                 delta = gs_p->c[RN] - old;
2034                                                 gs_p->c[AN] += delta;
2035                                         }
2036                                 } else {
2037                                         stemtip = gs_p->notelist[gs_p->nnotes-1]
2038                                                 .c[RY] - outstem;
2039                                         old = gs_p->c[RS];
2040                                         gs_p->c[RS] = MIN(stemtip, gs_p->c[RS])
2041                                                 - Stdpad;
2042                                         if (CSSpass == YES) {
2043                                                 delta = gs_p->c[RS] - old;
2044                                                 gs_p->c[AS] += delta;
2045
2046                                         }
2047                                 }
2048                         }
2049                 }
2050
2051                 if (CSSpass == NO) {
2052                         /*
2053                          * Increase RN and decrease RS based on "with" lists.
2054                          * Do this only in the first pass.  This depends on the
2055                          * fact that "with" lists are always put on the side
2056                          * away from the other staff, when CSS is involved.
2057                          */
2058                         expgroup(gs_p, ogs_p);
2059                 } else {
2060                         /*
2061                          * In the CSS pass, various group boundaries need more
2062                          * adjustment.
2063                          */
2064                         if (gs_p->stemdir == UP) {
2065                                 if (gs_p->stemto == CS_ABOVE && NNN(gs_p) == 0){
2066                                         gs_p->c[RS] = gs_p->notelist[
2067                                                 gs_p->nnotes-1].c[RS] - Stdpad;
2068                                         gs_p->c[AS] += gs_p->c[RS];
2069                                 }
2070                                 if (gs_p->stemto == CS_BELOW && NNN(gs_p) == 0){
2071                                         gs_p->c[RN] = gs_p->notelist[
2072                                                 gs_p->nnotes-1].c[RY] +
2073                                                 gs_p->stemlen;
2074                                         expgroup(gs_p, ogs_p);
2075                                         gs_p->c[AN] = gs_p->c[AY] + gs_p->c[RN];
2076                                 }
2077                                 if (gs_p->stemto == CS_SAME &&
2078                                                 gs_p->stemlen > 0) {
2079                                         gs_p->c[RN] = gs_p->notelist
2080                                         [gs_p->nnotes-1].c[RY] + gs_p->stemlen
2081                                         + Stdpad;
2082
2083                                         gs_p->c[AN] = gs_p->notelist
2084                                         [gs_p->nnotes-1].c[AY] + gs_p->stemlen
2085                                         + Stdpad;
2086                                 }
2087                                 if (gs_p->stemto == CS_ABOVE &&
2088                                                 gs_p->stemlen == 0) {
2089                                         gs_p->c[RN] = gs_p->notelist[0].c[RN]
2090                                                 + Stdpad;
2091                                         gs_p->c[AN] = gs_p->notelist[0].c[AN]
2092                                                 + Stdpad;
2093                                 }
2094                         } else {
2095                                 if (gs_p->stemto == CS_BELOW && NNN(gs_p) == 0){
2096                                         gs_p->c[RN] = gs_p->notelist[0].c[RN]
2097                                                 + Stdpad;
2098                                         gs_p->c[AN] += gs_p->c[RN];
2099                                 }
2100                                 if (gs_p->stemto == CS_ABOVE && NNN(gs_p) == 0){
2101                                         gs_p->c[RS] = gs_p->notelist[0].c[RY] -
2102                                                 gs_p->stemlen;
2103                                         expgroup(gs_p, ogs_p);
2104                                         gs_p->c[AS] = gs_p->c[AY] + gs_p->c[RS];
2105                                 }
2106                                 if (gs_p->stemto == CS_SAME &&
2107                                                 gs_p->stemlen > 0) {
2108                                         gs_p->c[RS] = gs_p->notelist[0].c[RY]
2109                                                 - gs_p->stemlen - Stdpad;
2110
2111                                         gs_p->c[AS] = gs_p->notelist[0].c[AY]
2112                                                 - gs_p->stemlen - Stdpad;
2113                                 }
2114                                 if (gs_p->stemto == CS_BELOW &&
2115                                                 gs_p->stemlen == 0) {
2116                                         gs_p->c[RS] = gs_p->notelist
2117                                                 [gs_p->nnotes-1].c[RS] - Stdpad;
2118                                         gs_p->c[AS] = gs_p->notelist
2119                                                 [gs_p->nnotes-1].c[AS] - Stdpad;
2120                                 }
2121                         }
2122                 }
2123         }
2124 }
2125 \f
2126 /*
2127  * Name:        settuplet()
2128  *
2129  * Abstract:    Figure out where tuplet bracket goes and change RN and RS.
2130  *
2131  * Returns:     void
2132  *
2133  * Description: This function is given a pointer to the first GRPSYL in a
2134  *              tuplet whose bracket is to be printed.  It figures out where
2135  *              the tuplet bracket and number should go, and sets tupextend for
2136  *              all the groups, to show where the tuplet bracket would go.
2137  *              Even if the bracket ends up not getting printed, this is needed
2138  *              for placing the number.
2139  */
2140
2141 static void
2142 settuplet(start_p, staff_p)
2143
2144 struct GRPSYL *start_p;         /* first group in the tuplet */
2145 struct STAFF *staff_p;          /* staff the tuplet is on */
2146
2147 {
2148         struct GRPSYL *gs_p;    /* loop through the groups in the tuplet */
2149         struct GRPSYL *last_p;  /* point the last group in the tuplet */
2150         struct GRPSYL *end_p;   /* point beyond the last group in the tuplet */
2151         struct NOTE *note_p;    /* pointer to an outside note of a group */
2152         float sx, sy;           /* sum of x and y coords of north or south */
2153         float xbar, ybar;       /* average x and y coords of north or south */
2154         float top, bottom;      /* numerator & denominator for finding b1 */
2155         float temp;             /* scratch variable */
2156         float startx, endx;     /* x coord of first and last north or south */
2157         float starty, endy;     /* y coord of first and last north or south */
2158         float b0, b1;           /* y intercept and slope */
2159         float maxb0, minb0;     /* max and min y intercepts */
2160         float shift;            /* x dist bracket reaches beyond end groups */
2161         float acceast, accwest; /* horizontal coords of an accidental */
2162         float accvert;          /* north or south of an accidental */
2163         float asc, des, wid;    /* ascent, descent, and width of an acc */
2164         float numeast, numwest; /* horizontal coords of the tuplet number */
2165         float numvert;          /* vertical edge of number closest to staff */
2166         float height;           /* height of the tuplet number */
2167         int css_affects_tup;    /* does CSS affect any group in the tuplet? */
2168         int coord;              /* RN or RS, depending on where bracket goes */
2169                                 /* or AN or AS if CSSpass == YES */
2170         int halfstaff;          /* half the height of staff, in stepsizes */
2171         int num;                /* number of groups in tuplet */
2172         float vert[2];          /* vertical coords of two groups */
2173         int n;                  /* loop variable */
2174
2175
2176         debug(32, "settuplet file=%s line=%d", start_p->inputfile,
2177                         start_p->inputlineno);
2178         /*
2179          * If start_p is pointing at a grace group that precedes the first real
2180          * group of the tuplet, move start_p forward to the first real group.
2181          * Actually, this shouldn't be necessary; the parser is doing it now.
2182          */
2183         while (start_p->grpvalue == GV_ZERO)
2184                 start_p = start_p->next;
2185
2186         /*
2187          * Find out which side the tuplet number (and bracket, if needed)
2188          * should go on.  That determines which coord we pay attention to.
2189          * The other determining factor is whether this is the CSS pass.
2190          */
2191         if (tupdir(start_p, staff_p) == PL_ABOVE) {
2192                 coord = CSSpass == YES ? AN : RN;
2193         } else {
2194                 coord = CSSpass == YES ? AS : RS;
2195         }
2196
2197         /* find whether CSS affects any group in the set */
2198         css_affects_tup = NO;
2199         if (CSSused == YES) {   /* don't waste time looking if CSS not used */
2200                 for (gs_p = start_p; gs_p != 0 && ! (gs_p != start_p &&
2201                                         gs_p->prev->tuploc == ENDITEM);
2202                                         gs_p = gs_p->next) {
2203                         if (gs_p->stemto == CS_ABOVE &&
2204                                                 (coord == AN || coord == AN) ||
2205                             gs_p->stemto == CS_BELOW &&
2206                                                 (coord == AS || coord == AS)) {
2207                                 css_affects_tup = YES;
2208                                 break;
2209                         }
2210                 }
2211         }
2212
2213         /*
2214          * If no groups are affected by CSS, handle this tuplet on the
2215          * first pass only.  If some are affected, handle it on the second
2216          * pass only.
2217          */
2218         if (css_affects_tup != CSSpass) {
2219                 return;
2220         }
2221
2222         last_p = 0;     /* prevent useless 'used before set' warnings */
2223
2224         /*
2225          * If the first group is STARTITEM, there are multiple groups in the
2226          * tuplet.  If it is LONEITEM, there is only one.
2227          */
2228         if (start_p->tuploc == STARTITEM) {
2229                 /*
2230                  * Use linear regression to find the best-fit line through the
2231                  * RN or RS, or AN or AS, of the groups, as the case may be.
2232                  * The X coords used are absolute, but the Y coords are, in the
2233                  * normal (non-CSSpass case) relative to the center line of the
2234                  * staff, since we don't know the absolute Y coords yet, and it
2235                  * wouldn't affect the result anyway.  But if this is the CSS
2236                  * pass, we do know the absolute vertical coords, and we have
2237                  * to use them, since we are dealing with two staffs.
2238                  *
2239                  * First get sum of x and y coords, to find averages.  Remember
2240                  * where last valid group is.  Only nongrace groups can be
2241                  * tuplet members, although there could be grace groups before
2242                  * a tuplet member.  We ignored any grace group before the
2243                  * first real tuplet member, but any others must be dealt with.
2244                  */
2245                 sx = sy = 0;
2246                 num = 0;
2247                 for (gs_p = start_p; gs_p != 0 && ! (gs_p != start_p &&
2248                                         gs_p->prev->tuploc == ENDITEM);
2249                                         gs_p = gs_p->next) {
2250                         sx += gs_p->c[AX];
2251                         sy += gs_p->c[coord];
2252                         num++;                  /* count number of groups */
2253                         last_p = gs_p;
2254                 }
2255                 /* last_p now points at last valid group */
2256
2257                 end_p = gs_p;   /* point end_p beyond last tuplet member */
2258
2259                 xbar = sx / num;
2260                 ybar = sy / num;
2261
2262                 /* accum numerator & denominator of regression formula for b1 */
2263                 top = bottom = 0;
2264                 for (gs_p = start_p; gs_p != end_p; gs_p = gs_p->next) {
2265                         temp = gs_p->c[AX] - xbar;
2266                         top += temp * (gs_p->c[coord] - ybar);
2267                         bottom += temp * temp;
2268                 }
2269
2270                 b1 = top / bottom;              /* slope */
2271                 /*
2272                  * We could also figure:
2273                  *      b0 = ybar - b1 * xbar;          y intercept
2274                  * to get the equation of the regression line:  y = b0 + b1 * x
2275                  * but we're going to change b0 later anyway.  Now, there are
2276                  * certain cases where we want to override the slope determined
2277                  * by regression, so revise b1 if that is the case.
2278                  */
2279
2280                 /* if first and last groups are equal, force horizontal */
2281                 if (start_p->c[coord] == last_p->c[coord])
2282                         b1 = 0.0;
2283
2284                 /* if repeating pattern of two coords, force horizontal */
2285                 if (b1 != 0.0 && num >= 4 && num % 2 == 0) {
2286                         vert[0] = start_p->c[coord];
2287                         vert[1] = start_p->next->c[coord];
2288                         for (n = 0, gs_p = start_p; n < num;
2289                                         n++, gs_p = gs_p->next) {
2290                                 if (n >= 2 && gs_p->c[coord] != vert[n % 2])
2291                                         break;
2292                         }
2293                         if (n == num)
2294                                 b1 = 0.0;
2295                 }
2296
2297         } else {        /* LONEITEM */
2298                 /*
2299                  * There's only one group, so there's no need to apply linear
2300                  * regression.  But we need to set up certain variables so that
2301                  * later code in this function can treat both cases the same.
2302                  */
2303                 last_p = start_p;       /* point at last tuplet member */
2304                 end_p = start_p->next;  /* point beyond last tuplet member */
2305                 b1 = 0;                 /* set horizontal slope */
2306                 b0 = start_p->c[coord]; /* y intercept based on this group */
2307         }
2308
2309         /*
2310          * Find half the width of a note head; the end of the tuplet bracket
2311          * reaches that far beyond the X coords of the outer groups.  Set
2312          * the X positions for these ends.
2313          */
2314         shift = getstemshift(last_p);
2315         startx = start_p->c[AX] - shift;        /* start of tuplet bracket */
2316         endx = last_p->c[AX] + shift;           /* end of tuplet bracket */
2317
2318         /*
2319          * The original line derived by linear regression must be adjusted in
2320          * certain ways.  First, don't let the slope exceed plus or minus 0.7,
2321          * since that would look bad.
2322          */
2323         if (b1 > 0.7)
2324                 b1 = 0.7;
2325         else if (b1 < -0.7)
2326                 b1 = -0.7;
2327
2328         /*
2329          * Calculate a new y intercept (b0).  First pass parallel lines
2330          * through each group's extremity, and record the maximum and minimum
2331          * y intercepts that result.
2332          */
2333         b0 = start_p->c[coord] - b1 * start_p->c[AX];
2334         maxb0 = minb0 = b0;             /* init to value for first group */
2335         /* look at rest of them */
2336         for (gs_p = start_p; gs_p != end_p; gs_p = gs_p->next) {
2337                 b0 = gs_p->c[coord] - b1 * gs_p->c[AX];
2338                 if (b0 > maxb0)
2339                         maxb0 = b0;
2340                 else if (b0 < minb0)
2341                         minb0 = b0;
2342         }
2343
2344         /*
2345          * The outer edge of the tuplet bracket, including the number, should
2346          * be TUPHEIGHT away from the group that sticks out the farthest.
2347          */
2348         if (coord == RN || coord == AN) {
2349                 b0 = maxb0 + Tupheight;
2350         } else {        /* RS or AS */ 
2351                 b0 = minb0 - Tupheight;
2352         }
2353
2354         /*
2355          * Calculate the Y positions of the start and end of the bracket from
2356          * the X positions, and the slope and Y intercept we have tentatively
2357          * chosen.  If, however, the bracket is going to fall within the staff,
2358          * make adjustments so it won't.
2359          */
2360         starty = b0 + b1 * startx;      /* y coord near left end of beam */
2361         endy = b0 + b1 * endx;          /* y coord near right end of beam */
2362         halfstaff = svpath(staff_p->staffno, STAFFLINES)->stafflines == 5
2363                         ? 4 : 1;
2364
2365         if (coord == RN) {
2366                 if (starty < halfstaff * Stepsize + Tupheight)
2367                         starty = halfstaff * Stepsize + Tupheight;
2368                 if (endy < halfstaff * Stepsize + Tupheight)
2369                         endy = halfstaff * Stepsize + Tupheight;
2370         } else if (coord == RS) {
2371                 if (starty > -halfstaff * Stepsize - Tupheight)
2372                         starty = -halfstaff * Stepsize - Tupheight;
2373                 if (endy > -halfstaff * Stepsize - Tupheight)
2374                         endy = -halfstaff * Stepsize - Tupheight;
2375         }
2376
2377         /*
2378          * If y at the ends of the bracket only differs by less than 2 points,
2379          * set end equal to the start to avoid a jagged look.
2380          */
2381         if (endy - starty < 2 * POINT && endy - starty > -2 * POINT) {
2382                 endy = (starty + endy) / 2.;
2383                 starty = endy;
2384         }
2385
2386         /* recalculate slope and y intercept from (possibly) new endpoints */
2387         b1 = (endy - starty) / (endx - startx);         /* slope */
2388         b0 = starty - b1 * startx;                      /* y intercept */
2389
2390         /*
2391          * The vertical extension of accidentals is not included in group
2392          * boundaries, and so the calculation of the tuplet bracket's equation
2393          * has ignored them so far.  In general, this is no problem.  If an
2394          * accidental touches or slightly crosses that line, who cares?  But we
2395          * would like to keep it from running into the tuplet number.  So scan
2396          * through the notes closest to the bracket, checking for accidentals.
2397          * (Notes a step or more from there would never really be a problem.)
2398          * Also, accidentals on the first group can never be a problem.
2399          */
2400         (void)tupnumsize(start_p, &numwest, &numeast, &height, staff_p);
2401         numvert = (starty + endy) / 2 + (coord == RN || coord == AN ?
2402                         -height : height) / 2;
2403
2404         for (gs_p = start_p->next; gs_p != end_p; gs_p = gs_p->next) {
2405
2406                 if (gs_p->grpcont != GC_NOTES)
2407                         continue;
2408
2409                 note_p = &gs_p->notelist[ coord == RN || coord == AN ?
2410                                 0 : gs_p->nnotes - 1 ];
2411                 if (note_p->accidental == '\0')
2412                         continue;
2413
2414                 /*
2415                  * The note of this group nearest the bracket has an acci-
2416                  * dental.  Find its horizontal midpoint, and vertical coord
2417                  * nearest the bracket.  Add padding to the vertical coord.
2418                  */
2419                 accdimen(note_p, &asc, &des, &wid);
2420                 asc *= Staffscale;
2421                 des *= Staffscale;
2422                 wid *= Staffscale;
2423
2424                 accwest = gs_p->c[AX] + note_p->waccr;
2425                 acceast = accwest + wid;
2426
2427                 if (coord == RN || coord == AN) {
2428                         accvert = note_p->c[CSSpass == YES ? AY : RY]
2429                                         + asc + Stepsize;
2430                 } else {
2431                         accvert = note_p->c[CSSpass == YES ? AY : RY]
2432                                         - des - Stepsize;
2433                 }
2434
2435                 /* if acc is completely to the left of the number, try next */
2436                 if (acceast < numwest)
2437                         continue;
2438
2439                 /* if acc is completely to the right, get out */
2440                 if (accwest > numeast)
2441                         break;
2442
2443                 /*
2444                  * If acc sticks out beyond the edge of the number, change the
2445                  * y intercept by that amount to prevent it.  Then get out,
2446                  * since no later groups could be that nearby.
2447                  */
2448                 if ((coord == RN || coord == AN) && accvert > numvert ||
2449                     (coord == RS || coord == AS) && accvert < numvert) {
2450                         b0 += accvert - numvert;
2451                         break;
2452                 }
2453         }
2454
2455         /*
2456          * At this point we know where to put the tuplet bracket.  Set
2457          * tupextend in all the groups, to reach the tuplet bracket.
2458          */
2459         for (gs_p = start_p; gs_p != end_p; gs_p = gs_p->next)
2460                 gs_p->tupextend = (b0 + b1 * gs_p->c[AX]) - gs_p->c[coord];
2461 }
2462 \f
2463 /*
2464  * Name:        expgroup()
2465  *
2466  * Abstract:    Decide side for "with" list & expand vertical group vertically.
2467  *
2468  * Returns:     void
2469  *
2470  * Description: This function decides which side of the group a "with" list
2471  *              should be put, and calls applywith() to alter the group's
2472  *              vertical boundaries accordingly.
2473  */
2474
2475 static void
2476 expgroup(gs_p, ogs_p)
2477
2478 struct GRPSYL *gs_p;    /* the group to be worked on */
2479 struct GRPSYL *ogs_p;   /* the other group */
2480
2481 {
2482         struct GRPSYL *g_p;     /* earlier GRPSYLs in *gs_p's list */
2483         RATIONAL vtime;         /* time preceding this group in measure */
2484         int side;               /* side to put things on (1=top, -1=bottom) */
2485
2486
2487         side = 0;       /* prevent useless 'used before set' warnings */
2488
2489         /*
2490          * Define a chunk of code for the cases where the stem may be allowed
2491          * to go either way.  It goes opposite the stem for normal, with the
2492          * stem for tab.
2493          */
2494 #define FREESTEM                                                        \
2495         {                                                               \
2496                 if (is_tab_staff(gs_p->staffno) == YES) {               \
2497                         side = -1;      /* we know stemdir is DOWN */   \
2498                         gs_p->normwith = NO;                            \
2499                 } else {                                                \
2500                         side = gs_p->stemdir == UP ? -1 : 1;            \
2501                         gs_p->normwith = YES;                           \
2502                 }                                                       \
2503         }
2504
2505         /*
2506          * Define a chunk of code for the cases where the stem has to go a
2507          * certain way, determined by which voice this is, unless forced by the
2508          * user.  The "with" items are always above a voice acting as voice 1,
2509          * and below a voice acting as voice 2.
2510          */
2511 #define FIXEDSTEM                                                       \
2512         {                                                               \
2513                 if (gs_p->pvno == 1) {                                  \
2514                         side = 1;                                       \
2515                         gs_p->normwith = gs_p->stemdir == UP ? NO : YES;\
2516                 } else {                                                \
2517                         side = -1;                                      \
2518                         gs_p->normwith = gs_p->stemdir == DOWN ? NO : YES;\
2519                 }                                                       \
2520         }
2521
2522         /*
2523          * If there is cross staff stemming, that consideration overrides all
2524          * others.  We want to keep the "with" items towards our staff, hoping
2525          * they will be less likely to collide with something there.
2526          */
2527         if (gs_p->stemto != CS_SAME) {
2528                 if (gs_p->stemto == CS_ABOVE) {
2529                         gs_p->normwith = gs_p->stemdir == UP ? YES : NO;
2530                         side = -1;
2531                 } else {        /*  CS_BELOW */
2532                         gs_p->normwith = gs_p->stemdir == UP ? NO : YES;
2533                         side = 1;
2534                 }
2535                 applywith(gs_p, side);
2536                 return;
2537         }
2538
2539         /*
2540          * Switch on vscheme to decide which side of the group the "with"
2541          * things will be put on.
2542          */
2543         switch (svpath(gs_p->staffno, VSCHEME)->vscheme) {
2544         case V_1:
2545                 FREESTEM
2546                 break;
2547
2548         case V_2OPSTEM:
2549                 FIXEDSTEM
2550                 break;
2551
2552         case V_2FREESTEM:
2553                 /*
2554                  * Figure out where this group starts by adding up the time
2555                  * values of all previous groups in the measure.  Then, treat
2556                  * this like V_1 or V_2OPSTEM, based on whether the other
2557                  * voice has space here.
2558                  */
2559                 vtime = Zero;
2560                 for (g_p = gs_p->prev; g_p != 0; g_p = g_p->prev)
2561                         vtime = radd(vtime, g_p->fulltime);
2562
2563                 if (hasspace(ogs_p, vtime, radd(vtime, gs_p->fulltime))) {
2564                         FREESTEM
2565                 } else {
2566                         FIXEDSTEM
2567                 }
2568                 break;
2569
2570         case V_3OPSTEM:
2571                 if (gs_p->pvno == 3) {
2572                         FREESTEM        /* voice 3 is always like V_1 */
2573                 } else {
2574                         FIXEDSTEM
2575                 }
2576                 break;
2577
2578         case V_3FREESTEM:
2579                 if (gs_p->pvno == 3) {
2580                         FREESTEM        /* voice 3 is always like V_1 */
2581                 } else {
2582                         /* voices 1 and 2 act like V_2FREESTEM */
2583                         vtime = Zero;
2584                         for (g_p = gs_p->prev; g_p != 0; g_p = g_p->prev)
2585                                 vtime = radd(vtime, g_p->fulltime);
2586
2587                         if (hasspace(ogs_p, vtime, radd(vtime, gs_p->fulltime))) {
2588                                 FREESTEM
2589                         } else {
2590                                 FIXEDSTEM
2591                         }
2592                 }
2593                 break;
2594         }
2595
2596         /*
2597          * If there is cross staff beaming and the "with" items are to be on
2598          * the beam side, we can't do anything yet since we don't know yet
2599          * where the beam will be.
2600          */
2601         if (gs_p->beamto != CS_SAME && gs_p->normwith == NO) {
2602                 return;
2603         }
2604
2605         applywith(gs_p, side);
2606 }
2607 \f
2608 /*
2609  * Name:        applywith()
2610  *
2611  * Abstract:    Expand vertical boundaries of group, based on "with" list.
2612  *
2613  * Returns:     void
2614  *
2615  * Description: This function adds to the RN coord of a group and/or subtracts
2616  *              from the RS coord, if a "with" list is present.
2617  */
2618
2619 static void
2620 applywith(gs_p, side)
2621
2622 struct GRPSYL *gs_p;    /* the group to be worked on */
2623 int side;               /* side to put things on (1=top, -1=bottom) */
2624
2625 {
2626         int n;                  /* loop variable */
2627         float hi;               /* height of a list item */
2628
2629
2630         /*
2631          * Loop through all the "with" items, expanding the N or S coord of
2632          * the group.  Each item is allowed enough space for its height, or
2633          * MINWITHHEIGHT, whichever is greater.  In the print phase, items of
2634          * height less than MINWITHHEIGHT will be placed so as to avoid staff
2635          * lines as much as possible.
2636          */
2637         for (n = 0; n < gs_p->nwith; n++) {
2638                 hi = strheight(gs_p->withlist[n]);
2639                 hi = MAX(hi, Staffscale * MINWITHHEIGHT);
2640                 if (side == 1)
2641                         gs_p->c[RN] += hi;
2642                 else
2643                         gs_p->c[RS] -= hi;
2644         }
2645 }