1 /* Copyright (c) 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005 by Arkkra Enterprises */
2 /* All rights reserved */
6 * Description: This file contains functions for setting lengths of note
7 * stems, which also involves beaming considerations.
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.
18 static float Defstemsteps;
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));
42 * Abstract: Set stem lengths for all notes that have stems or slash/alt.
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.
55 register struct MAINLL *mainll_p; /* point along main linked list */
56 int n; /* loop variable */
59 debug(16, "beamstem CSSpass=%d", CSSpass);
60 initstructs(); /* clean out old SSV info */
63 * Loop once for each item in the main linked list. Apply any SSVs
66 for (mainll_p = Mainllhc_p; mainll_p != 0; mainll_p = mainll_p->next) {
67 if (mainll_p->str == S_SSV) {
69 asgnssv(mainll_p->u.ssv_p);
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])) {
75 * For this visible staff, call a subroutine to process
76 * each list of groups on it.
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->
83 n + 1, STEMLEN)->stemlen;
84 if (is_tab_staff(mainll_p->u.staff_p->
86 proctablist(mainll_p, n);
88 proclist(mainll_p, n);
99 * Abstract: Process linked list of groups.
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.
114 proclist(mainll_p, vno)
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 */
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 */
130 debug(32, "proclist file=%s line=%d vno=%d", mainll_p->inputfile,
131 mainll_p->inputlineno, vno);
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.
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 ];
143 staff_p = mainll_p->u.staff_p; /* also point at staff */
145 /* set globals like Staffscale for use by the rest of the file */
146 set_staffscale(staff_p->staffno);
148 beamst_p = 0; /* prevent useless 'used before set' warnings */
151 * Loop through every group, skipping rests, spaces, and nongrace
152 * groups, setting the stem length of grace groups.
154 for (savegs_p = gs_p; gs_p != 0; gs_p = gs_p->next) {
155 if (gs_p->grpcont != GC_NOTES)
157 if (gs_p->grpvalue == GV_NORMAL)
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
166 if (gs_p->beamloc != NOITEM) {
167 if (gs_p->beamloc == STARTITEM)
169 if (gs_p->beamloc == ENDITEM)
170 setbeam(beamst_p, nextsimilar(gs_p), ogs_p);
175 /* if we get here, this group is not in a beamed set */
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) {
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.
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;
200 * Grace quarter notes default to just a note head and no stem.
201 * So set their stem length to 0.
203 if (gs_p->basictime == 4) {
209 * If stemlen parm is zero, force length to zero. This will
210 * look bad for non-quarter notes, but that's what they
213 if (Defstemsteps == 0.0) {
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
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];
229 /* set len to default length + distance between outer notes */
230 gs_p->stemlen = (Defstemsteps * SM_STEMFACTOR) * Stepsize +
233 bf = drmo(gs_p->basictime) - 2; /* no. of beams/flags */
235 gs_p->stemlen += (bf - 2) * Smflagsep;
239 * Loop through every grace group, skipping rests and spaces,
240 * setting the relative vertical coordinates.
242 setgroupvert(GV_ZERO, savegs_p, ogs_p);
245 * Loop through every group, skipping rests, spaces and grace groups,
246 * setting the stem length of all nongrace groups.
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
252 for (gs_p = savegs_p; gs_p != 0; gs_p = gs_p->next) {
253 if (gs_p->grpcont != GC_NOTES)
255 if (gs_p->grpvalue == GV_ZERO)
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
262 if (gs_p->beamto != CS_SAME) {
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
272 if (gs_p->beamloc != NOITEM) {
273 if (gs_p->beamloc == STARTITEM)
275 if (gs_p->beamloc == ENDITEM)
276 setbeam(beamst_p, nextsimilar(gs_p), ogs_p);
280 /* if we get here, this group is not in a beamed set */
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) {
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.
294 if (gs_p->basictime <= 1 && gs_p->slash_alt == 0)
295 continue; /* no stem and no pseudo stem */
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
303 if (IS_STEMLEN_KNOWN(gs_p->stemlen)) {
304 if (gs_p->stemlen == 0.0)
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;
314 /* if stemlen parm is zero, force length to zero */
315 if (Defstemsteps == 0.0) {
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
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;
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*/
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, ... */
345 gs_p->stemlen += (bf - 2) * Flagsep;
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.
352 if (gs_p->basictime >= 8 && gs_p->stemdir == UP &&
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;
359 gs_p->stemlen += 2 * Stepsize;
361 /* note is on a space */
362 if (gs_p->basictime > 8)
363 gs_p->stemlen += Stepsize;
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.
373 if (gs_p->basictime >= 2 && gs_p->grpsize == GS_NORMAL &&
374 vno != 2 && stemforced(gs_p, ogs_p) == NO &&
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
383 if (gs_p->stemdir == DOWN && gs_p->notelist[ 0 ].c[RY]
385 gs_p->stemlen = gs_p->notelist[ 0 ].c[RY];
391 * Loop through every nongrace group, skipping rests and spaces,
392 * setting the relative vertical coordinates.
394 setgroupvert(GV_NORMAL, savegs_p, ogs_p);
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.
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);
413 * Name: proctablist()
415 * Abstract: Process linked list of groups on a tablature staff.
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.
426 proctablist(mainll_p, vno)
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 */
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) */
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) {
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.
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 ];
458 * Loop through every group, setting some group vertical coordinates.
460 for ( ; gs_p != 0; gs_p = gs_p->next) {
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.
470 * Slashes and "with" lists are allowed only if there are
471 * frets, so if there aren't any frets, skip the rest.
473 if (gs_p->grpcont != GC_NOTES || gs_p->nnotes == 0)
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.
480 if (gs_p->slash_alt == 0) {
481 gs_p->stemlen = 0; /* no slashes */
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;
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 +
493 bf = abs(gs_p->slash_alt); /* slashes */
494 if (gs_p->basictime >= 16)
495 bf++; /* slashes need extra 1 if 16, 32, ...*/
497 gs_p->stemlen += (bf - 2) * Flagsep;
499 if (gs_p->stemdir == UP) {
500 gs_p->c[RN] = gs_p->notelist[gs_p->nnotes - 1]
501 .c[RN] + gs_p->stemlen;
503 gs_p->c[RS] = gs_p->notelist[0]
504 .c[RY] - gs_p->stemlen;
508 /* decrease RS based on "with" lists */
509 expgroup(gs_p, ogs_p);
516 * Abstract: Did the user force stem(s) to go the wrong way?
518 * Returns: YES at least one group was forced
519 * NO no groups were forced
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
529 stemforced(gs_p, ogs_p)
531 struct GRPSYL *gs_p; /* the group we are asking about */
532 struct GRPSYL *ogs_p; /* first group in other voice's linked list */
535 RATIONAL starttime; /* of the group in question */
536 RATIONAL endtime; /* of the group in question */
537 struct GRPSYL *gs2_p; /* loop through groups */
540 /* voice 3 never cares, so is never considered to be forced */
541 if (gs_p->vno == 3) {
545 /* grace cannot be forced */
546 if (gs_p->grpvalue == GV_ZERO) {
550 switch (svpath(gs_p->staffno, VSCHEME)->vscheme) {
552 return (NO); /* no forcing is needed in this vscheme */
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.
560 if (gs_p->vno == 1 && gs_p->stemdir == DOWN ||
561 gs_p->vno == 2 && gs_p->stemdir == UP) {
568 * We are in one of the freestem vschemes.
571 /* if the other voice doesn't exist, we know we were not forced */
573 return (NO); /* other voice does not exist */
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) {
582 /* check if the other voice is all spaces during this time */
584 /* find start time of *gs_p by summing all previous groups */
586 for (gs2_p = gs_p->prev; gs2_p != 0; gs2_p = gs2_p->prev) {
587 starttime = radd(starttime, gs2_p->fulltime);
590 /* find end time of *gs_p (or the whole beamed set) */
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) {
600 if (hasspace(ogs_p, starttime, endtime) == YES) {
601 return (NO); /* all spaces, forcing was not needed */
603 return (YES); /* notes/rests, we were forced */
610 * Abstract: Set stem lengths for a beamed set of groups.
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.
623 * Groups involved in cross staff beaming should never call here.
624 * That work must be done later in absvert.c.
628 setbeam(start_p, end_p, ogs_p)
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 */
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 */
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.
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;
690 if (all_notes_other_staff == YES) {
691 css_affects_beam = YES;
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
700 if (css_affects_beam != CSSpass) {
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.
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);
722 last_p = 0; /* prevent useless 'used before set' warnings */
724 /* find the last valid group */
725 for (gs_p = start_p; gs_p != end_p; gs_p = nextsimilar(gs_p)) {
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.
735 one_end_forced = IS_STEMLEN_KNOWN(start_p->stemlen) !=
736 IS_STEMLEN_KNOWN(last_p->stemlen);
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
743 if (IS_STEMLEN_KNOWN(start_p->stemlen) &&
744 IS_STEMLEN_KNOWN(last_p->stemlen)) {
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
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)) {
756 restore_ry(start_p, end_p);
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;
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);
775 /* find slope and y intercept of line through those points */
776 b1 = (starty - endy) / (startx - endx);
777 b0 = starty - b1 * startx;
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 */
783 /* first set stemlen to beam's Y coord minus note's */
784 gs_p->stemlen = (b0 + b1 * x) - BNOTE(gs_p).c[RY];
786 /* if stems are down, reverse it */
787 if (gs_p->stemdir == DOWN)
788 gs_p->stemlen = -(gs_p->stemlen);
790 finalstemadjust(gs_p);
793 /* set relative vertical coords of any embedded rests */
794 embedrest(start_p, last_p, b1, b0);
796 restore_ry(start_p, end_p);
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.
805 if (fabs(start_p->beamslope - NOBEAMANGLE) < 0.001) {
807 forced_slope = 0.0; /* not used, keep lint happy */
810 forced_slope = tan(start_p->beamslope * PI / 180.0);
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
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)) {
826 restore_ry(start_p, end_p);
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.
840 * First get sum of x and y coords, to find averages.
844 for (gs_p = start_p; gs_p != end_p; gs_p = nextsimilar(gs_p)) {
846 sy += BNOTE(gs_p).c[RY];
847 num++; /* count number of notes */
853 /* accumulate numerator & denominator of regression formula for b1 */
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;
861 b1 = top / bottom; /* slope */
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.
871 /* if first and last notes are equal, force horizontal */
872 if (BNOTE(start_p).stepsup == BNOTE(last_p).stepsup)
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;
885 * Check for a repeating pattern of notes. Try every possible
886 * pattern length <= half as long as set. If found, force the
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 */
894 /* see if initial pattern repeats perfectly */
896 for (n = 0; n < patlen && match == YES; n++) {
897 for (k = n + patlen; k < num; k += patlen) {
898 if (steps[k] != steps[n]) {
904 /* if all repeats matched, force horizontal & break */
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.
918 /* make sure all the inner groups are the same */
920 for (n = 2; n < num - 1; n++) {
921 if (steps[n] != steps[1]) {
926 /* if inner groups same, check the other conditions */
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])) {
936 if ((steps[0] < steps[1] &&
937 steps[num-1] == steps[1]) ||
938 (steps[0] == steps[1] &&
939 steps[num-1] < steps[1])) {
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.)
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 */
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.
970 b1 = adjslope(start_p, b1, NO);
974 * Calculate a new y intercept (b0). First pass parallel lines
975 * through each note, and record the maximum and minimum y intercepts
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];
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.
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*/
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 */
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.
1009 if (gs_p != start_p && gs_p->stemdir == UP &&
1010 gs_p->notelist[0].accidental != '\0' &&
1011 gs_p->notelist[0].accidental != 'x' &&
1013 bf += 3.5 * b1 * (Stepsize / Flagsep) * ((bf > 1) +
1014 (gs_p->notelist[0].accidental == 'B'));
1019 if (allsmall(start_p, last_p) == NO) {
1020 /* at least one group has a normal size note */
1021 deflen = Defstemsteps * Stepsize;
1023 deflen += (shortest - 2) * Flagsep;
1025 /* all groups have all small notes */
1026 deflen = Defstemsteps * SM_STEMFACTOR * Stepsize;
1028 deflen += (shortest - 2) * 4.0 * POINT * Staffscale;
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.
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;
1045 if (maxb0 - minb0 > shortdist)
1046 b0 = minb0 - deflen + shortdist;
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.)
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) {
1064 /* move both ends the same amount to preserve slope */
1065 if (start_p->stemdir == UP) {
1085 /* move just the end(s) that need to be moved */
1086 if (start_p->stemdir == UP) {
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.
1106 if ( ! slope_forced && fabs(starty) < Stdpad &&
1107 fabs(endy) < Stdpad && b1 != 0.0) {
1108 if (start_p->stemdir == UP) {
1111 } else if (b1 < 0.0) {
1117 } else if (b1 < 0.0) {
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.
1129 if ( ! slope_forced && fabs(starty - endy) < Stepsize - 0.001) {
1130 if (start_p->stemdir == UP) {
1131 if (starty > endy) {
1137 if (starty < endy) {
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 */
1150 /* do some additional work for nongrace groups */
1151 if (start_p->grpvalue == GV_NORMAL) {
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.
1156 if (start_p->slash_alt >= 0)
1157 b0 = embedgrace(start_p, b1, b0);
1159 /* may need to lengthen stems to avoid embedded clefs */
1160 b0 = embedclef(start_p, b1, b0);
1162 /* set relative vertical coords of any embedded rests */
1163 embedrest(start_p, last_p, b1, b0);
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.
1170 b0 = avoidothervoice(start_p, last_p, b1, b0, ogs_p);
1172 /* update these by the amount the y intercept changed */
1173 starty += temp - b0;
1177 restore_ry(start_p, end_p);
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.
1186 if (one_end_forced) {
1187 if (IS_STEMLEN_KNOWN(start_p->stemlen)) {
1188 start_p->stemlen *= Staffscale;
1190 starty = BNOTE(start_p).c[RY] + start_p->stemlen *
1191 (start_p->stemdir == UP ? 1.0 : -1.0);
1193 endy += starty - temp;
1196 last_p->stemlen *= Staffscale;
1198 endy = BNOTE(last_p).c[RY] + last_p->stemlen *
1199 (last_p->stemdir == UP ? 1.0 : -1.0);
1201 starty += endy - temp;
1206 b1 = (endy - starty) / (endx - startx); /* slope */
1207 b0 = starty - b1 * startx; /* y intercept */
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.
1217 embedrest(start_p, last_p, b1, b0);
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.
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 */
1228 /* first set stemlen to beam's Y coord minus note's */
1229 gs_p->stemlen = (b0 + b1 * x) - BNOTE(gs_p).c[RY];
1231 /* if stems down, reverse stemlen, should make it positive */
1232 if (gs_p->stemdir == DOWN) {
1233 gs_p->stemlen = -(gs_p->stemlen);
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");
1241 finalstemadjust(gs_p);
1246 * Name: restore_ry()
1248 * Abstract: Restore RY coordinates if need be.
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.
1258 restore_ry(start_p, end_p)
1260 struct GRPSYL *start_p; /* first in beamed set */
1261 struct GRPSYL *end_p; /* after last in beamed set */
1264 struct GRPSYL *gs_p; /* loop through the groups in the beamed set */
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];
1277 * Name: embedgrace()
1279 * Abstract: Change the Y intercept if necessary for embedded grace groups.
1281 * Returns: new y intercept value (may be no change)
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.
1294 embedgrace(start_p, b1, b0)
1296 struct GRPSYL *start_p; /* first group in nongrace beamed set */
1297 double b1; /* slope */
1298 double b0; /* y intercept */
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 */
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.
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 */
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.)
1325 prev_p = prevnongrace(gs_p);
1326 next_p = nextnongrace(gs_p);
1328 /* thickness of relevant beams at right side of grace */
1329 beamthick = beamoff(next_p, PB_LEFT, gs_p->c[AE], start_p);
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.
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];
1346 /* thickness of relevant beams at left side of grace */
1347 beamthick = beamoff(prev_p, PB_RIGHT, gs_p->c[AW], start_p);
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];
1359 return (b0); /* new (possibly changed) Y intercept */
1365 * Abstract: Change the Y intercept if necessary for embedded clefs.
1367 * Returns: new y intercept value (may be no change)
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.
1379 embedclef(start_p, b1, b0)
1381 struct GRPSYL *start_p; /* first group in nongrace beamed set */
1382 double b1; /* slope */
1383 double b0; /* y intercept */
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 */
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.
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) {
1404 if (gs_p->clef == NOCLEF) {
1405 continue; /* ignore groups with no clef */
1408 /* find the vertical edges of the clef */
1409 (void)clefvert(gs_p->clef, YES, &north, &south);
1410 north *= Staffscale;
1411 south *= Staffscale;
1414 * Make sure the right side of the clef doesn't collide with
1417 /* find right side of the clef */
1418 horizontal = gs_p->c[AW] - CLEFPAD * Staffscale;
1420 /* group whose partial beams we need to worry about */
1421 pbgs_p = gs_p->grpvalue == GV_ZERO ? nextnongrace(gs_p) : gs_p;
1423 /* thickness of relevant beams at right side of clef */
1424 beamthick = beamoff(pbgs_p, PB_LEFT, horizontal, start_p);
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);
1433 } else { /* stemdir == DOWN */
1434 if (ycross + beamthick > south) {
1435 b0 -= (ycross + beamthick) - south;
1440 * Make sure the left side of the clef doesn't collide with
1443 /* find left side of the clef */
1444 horizontal -= clefwidth(gs_p->clef, YES) * Staffscale;
1446 /* group whose partial beams we need to worry about */
1447 pbgs_p = prevnongrace(gs_p);
1449 /* thickness of relevant beams at left side of clef */
1450 beamthick = beamoff(pbgs_p, PB_RIGHT, horizontal, start_p);
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);
1459 } else { /* stemdir == DOWN */
1460 if (ycross + beamthick > south) {
1461 b0 -= (ycross + beamthick) - south;
1466 return (b0); /* new (possibly changed) Y intercept */
1472 * Abstract: On one side of group, get height of beams and spaces between.
1474 * Returns: height in inches
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"
1485 beamoff(gs_p, side, boundary, start_p)
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 */
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 */
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
1504 if (side == PB_LEFT) {
1505 ogs_p = prevnongrace(gs_p);
1506 o2gs_p = nextnongrace(gs_p);
1508 ogs_p = nextnongrace(gs_p);
1509 o2gs_p = prevnongrace(gs_p);
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.)
1518 minbasic = MIN(gs_p->basictime, ogs_p->basictime);
1519 if (minbasic >= 8) {
1520 beams = drmo(MIN(gs_p->basictime, ogs_p->basictime)) - 2;
1522 beams = 0; /* must be an alternation */
1525 /* add the number of alternation beams, if any */
1526 if (gs_p->slash_alt < 0) {
1527 beams -= gs_p->slash_alt;
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 . . .
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)) {
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 . . .
1545 if (gs_p->beamloc == STARTITEM || gs_p->beamloc == ENDITEM ||
1546 gs_p->basictime > o2gs_p->basictime) {
1548 * We have partial beam(s); if on the side that matters
1549 * to us, reset the number of beams to include partials.
1551 if (pbeamside(gs_p, start_p) == side) {
1552 beams = drmo(gs_p->basictime) - 2;
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.
1561 return (Flagsep * beams + Stepsize / 2.0);
1567 * Abstract: Set relative vertical coords of rests embedded in beamed sets.
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.
1577 embedrest(start_p, last_p, b1, b0)
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 */
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 */
1599 * Loop through the interior groups of this set, setting relative
1600 * vertical coords of rest groups. (Outer groups are never rests.)
1602 for (gs_p = start_p->next; gs_p != last_p; gs_p = gs_p->next) {
1605 if (gs_p->grpcont != GC_REST)
1608 /* skip cases where the user is forcing the coords */
1609 if (gs_p->restdist != NORESTDIST)
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;
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)
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);
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)
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)
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);
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)
1650 /* get number of beams needed by prev and next */
1651 bp = numbeams(gp_p->basictime);
1652 bn = numbeams(gn_p->basictime);
1654 partial = 0; /* init to no partial beams */
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.
1661 if (gs_p->prev->grpcont == GC_NOTES && start_p->stemdir == UP
1664 /* definitely partial beams on this side */
1667 /* maybe partial beams on this side */
1668 if (numbeams(gpp_p->basictime) < bp &&
1669 pbeamside(gp_p, start_p) == PB_RIGHT)
1672 /* but if far enough away horizontally, we can ignore */
1673 if (gs_p->c[AW] - gp_p->c[AE] > 1.5 * Stepsize)
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.
1685 if (gs_p->next->grpcont == GC_NOTES && start_p->stemdir == DOWN
1688 /* definitely partial beams on this side */
1691 /* maybe partial beams on this side */
1692 if (numbeams(gnn_p->basictime) < bn &&
1693 pbeamside(gn_p, start_p) == PB_LEFT)
1696 /* but if far enough away horizontally, we can ignore */
1697 if (gn_p->c[AW] - gs_p->c[AE] > 1.5 * Stepsize)
1701 /* full beams joining prev and next, plus relevant partials */
1702 beams = MIN(bp, bn) + partial;
1705 * To get total beam thickness, multiply the size of one beam
1706 * by the number of beams.
1708 beamthick = Flagsep * beams;
1710 /* find where outer beam hits our rest's X coord */
1711 ycross = b1 * gs_p->c[AX] + b0;
1713 /* find vertical coord, quantizing the results */
1714 if (start_p->stemdir == UP) {
1715 gs_p->c[RY] = nearestline(ycross - beamthick -
1717 } else { /* stemdir == DOWN */
1718 gs_p->c[RY] = nearestline(ycross + beamthick +
1722 gs_p->c[RN] = gs_p->c[RY] + asc;
1723 gs_p->c[RS] = gs_p->c[RY] - des;
1728 * Name: avoidothervoice()
1730 * Abstract: Change the Y intercept if necessary to avoid the other voice.
1732 * Returns: new y intercept value (may be no change)
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.
1744 avoidothervoice(start_p, last_p, b1, b0, ogs_p)
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 */
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 */
1766 move = 0.0; /* init to no move */
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
1774 for (gs_p = ogs_p; gs_p != 0; gs_p = gs_p->next) {
1776 /* spaces and rests can't interfere with anything */
1777 if (gs_p->grpcont != GC_NOTES)
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])
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.
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))
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.
1800 if (next_p->c[AX] == gs_p->c[AX]) {
1801 if (next_p->grpcont == GC_NOTES)
1802 continue; /* compatible, no problem */
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.
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);
1818 } else { /* stemdir == DOWN */
1819 fary = gs_p->notelist[ gs_p->nnotes-1 ].c[RS]
1821 if (next_p->c[RN] > fary) {
1822 thismove = fary - next_p->c[RN];
1823 move = MIN(move, thismove);
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.
1836 if (prev_p->basictime >= 8)
1837 beams = drmo(MIN(prev_p->basictime, next_p->basictime))
1842 if (prev_p->slash_alt < 0)
1843 beams -= prev_p->slash_alt;
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
1852 if (prev_p->basictime < next_p->basictime && next_p->stemdir ==
1853 DOWN && next_p->c[AX] - gs_p->c[AX] < 5 * Stepsize) {
1855 /* find nongrace group after "next", if one exists */
1856 next2_p = nextnongrace(next_p);
1858 /* if "next" group has partial beams . . . */
1859 if (next2_p == 0 || next_p->beamloc == ENDITEM ||
1860 next_p->basictime > next2_p->basictime) {
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;
1866 } else if (prev_p->basictime > next_p->basictime && prev_p->
1867 stemdir == UP && gs_p->c[AX] - prev_p->c[AX] < 5 * Stepsize) {
1869 /* find nongrace group before "prev", if one exists */
1870 prev2_p = prevnongrace(prev_p);
1872 /* if "prev" group has partial beams . . . */
1873 if (prev2_p == 0 || prev_p->beamloc == STARTITEM ||
1874 prev_p->basictime > prev2_p->basictime) {
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;
1882 beamthick = Flagsep * beams + Stepsize;
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.
1892 ycross = b1 * gs_p->c[AX] + b0;
1893 if (start_p->stemdir == UP) {
1895 fary = gs_p->notelist[0].c[RN] + Stdpad;
1896 if (ycross - beamthick < fary) {
1897 thismove = fary - (ycross - beamthick);
1898 move = MAX(move, thismove);
1901 } else { /* stemdir == DOWN */
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);
1912 return (b0); /* no change; return old intercept */
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.
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)
1926 if (gs_p != last_p) {
1928 * We found a rest. Round the amount the intercept moved up to
1929 * a multiple of 2 stepsizes.
1931 move = (move < 0.0 ? -1.0 : 1.0) * 2.0 * Stepsize *
1932 ((int)(fabs(move) / (2.0 * Stepsize)) + 1);
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;
1944 return (b0 + move); /* new Y intercept */
1948 * Name: setgroupvert()
1950 * Abstract: Set RN and RS for each group of given type in a linked list.
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.
1961 setgroupvert(grpvalue, firstgs_p, ogs_p)
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 */
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 */
1975 debug(32, "setgroupvert file=%s line=%d grpvalue=%d",
1976 firstgs_p->inputfile, firstgs_p->inputlineno, grpvalue);
1978 * Loop through every group, skipping rests, spaces, and groups of the
1979 * wrong type (grace vs. nongrace), setting the relative vertical
1982 for (gs_p = firstgs_p; gs_p != 0; gs_p = gs_p->next) {
1983 if (gs_p->grpcont != GC_NOTES)
1985 if (gs_p->grpvalue != grpvalue)
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.
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.
2000 if (css_affects_stemtip(gs_p) == CSSpass) {
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.
2014 if (gs_p->beamto == CS_SAME &&
2015 (gs_p->basictime >= 2 || gs_p->slash_alt != 0) &&
2016 gs_p->stemlen != 0.0) {
2018 outstem = gs_p->stemlen
2019 - (gs_p->notelist[0].c[RY]
2020 - gs_p->notelist[gs_p->nnotes-1].c[RY]);
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.
2026 if (gs_p->stemdir == UP) {
2027 stemtip = gs_p->notelist[0].c[RY]
2030 gs_p->c[RN] = MAX(stemtip, gs_p->c[RN])
2032 if (CSSpass == YES) {
2033 delta = gs_p->c[RN] - old;
2034 gs_p->c[AN] += delta;
2037 stemtip = gs_p->notelist[gs_p->nnotes-1]
2040 gs_p->c[RS] = MIN(stemtip, gs_p->c[RS])
2042 if (CSSpass == YES) {
2043 delta = gs_p->c[RS] - old;
2044 gs_p->c[AS] += delta;
2051 if (CSSpass == NO) {
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.
2058 expgroup(gs_p, ogs_p);
2061 * In the CSS pass, various group boundaries need more
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];
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] +
2074 expgroup(gs_p, ogs_p);
2075 gs_p->c[AN] = gs_p->c[AY] + gs_p->c[RN];
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
2083 gs_p->c[AN] = gs_p->notelist
2084 [gs_p->nnotes-1].c[AY] + gs_p->stemlen
2087 if (gs_p->stemto == CS_ABOVE &&
2088 gs_p->stemlen == 0) {
2089 gs_p->c[RN] = gs_p->notelist[0].c[RN]
2091 gs_p->c[AN] = gs_p->notelist[0].c[AN]
2095 if (gs_p->stemto == CS_BELOW && NNN(gs_p) == 0){
2096 gs_p->c[RN] = gs_p->notelist[0].c[RN]
2098 gs_p->c[AN] += gs_p->c[RN];
2100 if (gs_p->stemto == CS_ABOVE && NNN(gs_p) == 0){
2101 gs_p->c[RS] = gs_p->notelist[0].c[RY] -
2103 expgroup(gs_p, ogs_p);
2104 gs_p->c[AS] = gs_p->c[AY] + gs_p->c[RS];
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;
2111 gs_p->c[AS] = gs_p->notelist[0].c[AY]
2112 - gs_p->stemlen - Stdpad;
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;
2129 * Abstract: Figure out where tuplet bracket goes and change RN and RS.
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.
2142 settuplet(start_p, staff_p)
2144 struct GRPSYL *start_p; /* first group in the tuplet */
2145 struct STAFF *staff_p; /* staff the tuplet is on */
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 */
2176 debug(32, "settuplet file=%s line=%d", start_p->inputfile,
2177 start_p->inputlineno);
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.
2183 while (start_p->grpvalue == GV_ZERO)
2184 start_p = start_p->next;
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.
2191 if (tupdir(start_p, staff_p) == PL_ABOVE) {
2192 coord = CSSpass == YES ? AN : RN;
2194 coord = CSSpass == YES ? AS : RS;
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;
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
2218 if (css_affects_tup != CSSpass) {
2222 last_p = 0; /* prevent useless 'used before set' warnings */
2225 * If the first group is STARTITEM, there are multiple groups in the
2226 * tuplet. If it is LONEITEM, there is only one.
2228 if (start_p->tuploc == STARTITEM) {
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.
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.
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) {
2251 sy += gs_p->c[coord];
2252 num++; /* count number of groups */
2255 /* last_p now points at last valid group */
2257 end_p = gs_p; /* point end_p beyond last tuplet member */
2262 /* accum numerator & denominator of regression formula for b1 */
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;
2270 b1 = top / bottom; /* slope */
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.
2280 /* if first and last groups are equal, force horizontal */
2281 if (start_p->c[coord] == last_p->c[coord])
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])
2297 } else { /* LONEITEM */
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.
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 */
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.
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 */
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.
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.
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];
2340 else if (b0 < minb0)
2345 * The outer edge of the tuplet bracket, including the number, should
2346 * be TUPHEIGHT away from the group that sticks out the farthest.
2348 if (coord == RN || coord == AN) {
2349 b0 = maxb0 + Tupheight;
2350 } else { /* RS or AS */
2351 b0 = minb0 - Tupheight;
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.
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
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;
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.
2381 if (endy - starty < 2 * POINT && endy - starty > -2 * POINT) {
2382 endy = (starty + endy) / 2.;
2386 /* recalculate slope and y intercept from (possibly) new endpoints */
2387 b1 = (endy - starty) / (endx - startx); /* slope */
2388 b0 = starty - b1 * startx; /* y intercept */
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.
2400 (void)tupnumsize(start_p, &numwest, &numeast, &height, staff_p);
2401 numvert = (starty + endy) / 2 + (coord == RN || coord == AN ?
2402 -height : height) / 2;
2404 for (gs_p = start_p->next; gs_p != end_p; gs_p = gs_p->next) {
2406 if (gs_p->grpcont != GC_NOTES)
2409 note_p = &gs_p->notelist[ coord == RN || coord == AN ?
2410 0 : gs_p->nnotes - 1 ];
2411 if (note_p->accidental == '\0')
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.
2419 accdimen(note_p, &asc, &des, &wid);
2424 accwest = gs_p->c[AX] + note_p->waccr;
2425 acceast = accwest + wid;
2427 if (coord == RN || coord == AN) {
2428 accvert = note_p->c[CSSpass == YES ? AY : RY]
2431 accvert = note_p->c[CSSpass == YES ? AY : RY]
2435 /* if acc is completely to the left of the number, try next */
2436 if (acceast < numwest)
2439 /* if acc is completely to the right, get out */
2440 if (accwest > numeast)
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.
2448 if ((coord == RN || coord == AN) && accvert > numvert ||
2449 (coord == RS || coord == AS) && accvert < numvert) {
2450 b0 += accvert - numvert;
2456 * At this point we know where to put the tuplet bracket. Set
2457 * tupextend in all the groups, to reach the tuplet bracket.
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];
2466 * Abstract: Decide side for "with" list & expand vertical group vertically.
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.
2476 expgroup(gs_p, ogs_p)
2478 struct GRPSYL *gs_p; /* the group to be worked on */
2479 struct GRPSYL *ogs_p; /* the other group */
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) */
2487 side = 0; /* prevent useless 'used before set' warnings */
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
2496 if (is_tab_staff(gs_p->staffno) == YES) { \
2497 side = -1; /* we know stemdir is DOWN */ \
2498 gs_p->normwith = NO; \
2500 side = gs_p->stemdir == UP ? -1 : 1; \
2501 gs_p->normwith = YES; \
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.
2513 if (gs_p->pvno == 1) { \
2515 gs_p->normwith = gs_p->stemdir == UP ? NO : YES;\
2518 gs_p->normwith = gs_p->stemdir == DOWN ? NO : YES;\
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.
2527 if (gs_p->stemto != CS_SAME) {
2528 if (gs_p->stemto == CS_ABOVE) {
2529 gs_p->normwith = gs_p->stemdir == UP ? YES : NO;
2531 } else { /* CS_BELOW */
2532 gs_p->normwith = gs_p->stemdir == UP ? NO : YES;
2535 applywith(gs_p, side);
2540 * Switch on vscheme to decide which side of the group the "with"
2541 * things will be put on.
2543 switch (svpath(gs_p->staffno, VSCHEME)->vscheme) {
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.
2560 for (g_p = gs_p->prev; g_p != 0; g_p = g_p->prev)
2561 vtime = radd(vtime, g_p->fulltime);
2563 if (hasspace(ogs_p, vtime, radd(vtime, gs_p->fulltime))) {
2571 if (gs_p->pvno == 3) {
2572 FREESTEM /* voice 3 is always like V_1 */
2579 if (gs_p->pvno == 3) {
2580 FREESTEM /* voice 3 is always like V_1 */
2582 /* voices 1 and 2 act like V_2FREESTEM */
2584 for (g_p = gs_p->prev; g_p != 0; g_p = g_p->prev)
2585 vtime = radd(vtime, g_p->fulltime);
2587 if (hasspace(ogs_p, vtime, radd(vtime, gs_p->fulltime))) {
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.
2601 if (gs_p->beamto != CS_SAME && gs_p->normwith == NO) {
2605 applywith(gs_p, side);
2611 * Abstract: Expand vertical boundaries of group, based on "with" list.
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.
2620 applywith(gs_p, side)
2622 struct GRPSYL *gs_p; /* the group to be worked on */
2623 int side; /* side to put things on (1=top, -1=bottom) */
2626 int n; /* loop variable */
2627 float hi; /* height of a list item */
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.
2637 for (n = 0; n < gs_p->nwith; n++) {
2638 hi = strheight(gs_p->withlist[n]);
2639 hi = MAX(hi, Staffscale * MINWITHHEIGHT);