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
);