2 /* Copyright (c) 1995, 1996, 1997, 1998, 1999, 2001, 2002, 2005 by Arkkra Enterprises */
3 /* All rights reserved */
5 /* functions to determine the curves that make up phrase marks,
12 /* distance to the top/bottom of a V-shape (indicating a bend) relative to
13 * the line connecting the endpoints of the V */
14 #define V_HEIGHT (2.7 * Stepsize)
16 /* How much bulge to allow in curves. There are three slightly different
17 * approaches that are tried, each succeeding approach allows more bulge
18 * in a more despearate attempt to get a reasonable curve. */
19 #define MINBULGE (1.2)
20 #define MAXBULGE (2.1)
21 #define MIN2BULGE (1.4)
22 #define MAX2BULGE (4.1)
23 #define MIN3BULGE (1.8)
24 #define MAX3BULGE (5.6)
26 /* We'd normally want curves to begin and end (in the x direction) exactly in
27 * the middle of their note. But if one curve ends and another begins on
28 * the same note, the curve endpoints would collide, which could look bad.
29 * So we always offset the endpoints by a tiny amount (ends end a little
30 * west of center, and beginnings begin a little east) so they don't touch.
31 * This is the amount they are shifted from center.
33 #define XOFFSET4CURVE (0.75 * Stdpad)
35 /* Curves must be at least this far away from notes */
36 #define CLEARANCE (3.0 * Stdpad)
38 /* try_bulge() is called lots of times in a row with mostly the same values,
39 * and it needs lots of values, so it is convenient to put them in a struct,
40 * and just pass a pointer to it */
42 struct MAINLL
*mll_p
; /* STUFF hangs off here */
43 struct GRPSYL
*begin_gs_p
; /* group at left end of curve */
44 struct GRPSYL
*end_gs_p
; /* group at right end of curve */
46 struct CRVLIST
*curvelist_p
; /* points to beginning of curve */
47 struct CRVLIST
*endlist_p
; /* points to end of curve */
48 double xlen
; /* distance to midpoint */
49 double ylen
; /* how much bulge to add */
50 double sintheta
; /* for rotation from horizontal */
52 double minbulge
; /* first bulge factor to try */
53 double maxbulge
; /* last bulge to try before giving up */
54 int leftcount
; /* value is returned here. Count of
55 * how many "stick-outs" are near the
56 * left end of the curve */
57 int rightcount
; /* similar for right end */
60 static int nowhere_slide
P((struct STUFF
*stuff_p
));
61 static void do_nowhere
P((struct STUFF
*stuff_p
, double x1
, double y1
,
62 double x2
, double y2
));
63 static void curve_points
P((struct MAINLL
*mll_p
, struct STUFF
*stuff_p
,
65 static double inner_adj
P((struct GRPSYL
*gs_p
, struct NOTE
*note_p
,
66 double y_adj
, int place
));
67 static double stick_out
P((struct TRYBULGE
*info_p
));
68 static double try_bulge
P((struct TRYBULGE
*info_p
));
69 static double tieslurx
P((struct GRPSYL
*gs_p
, struct NOTE
*note_p
, int place
));
70 static struct MAINLL
*next_staff
P((int staff
, struct MAINLL
*mll_p
));
71 static void redo_steep
P((struct CRVLIST
*first_p
, struct CRVLIST
*last_p
,
73 static void final_touches
P((struct MAINLL
*mll_p
, struct GRPSYL
*begin_gs_p
,
74 struct GRPSYL
*end_gs_p
, struct CRVLIST
*crvlist_p
, int place
));
75 static double eff_tupext
P((struct GRPSYL
* gs_p
, struct STAFF
*staff_p
, int side
));
76 static int bulge_direction
P((struct MAINLL
*mll_p
, struct GRPSYL
*gs1_p
,
77 int note_index
, int curveno
));
80 /* figure out what points are needed for a phrase mark */
81 /* attach a linked list of x,y coordinates that show where to draw the curve.
82 * The curve will be out of the way of any groups within the phrase. */
85 phrase_points(mll_p
, stuff_p
)
87 struct MAINLL
*mll_p
; /* MAINLL that stuff_p hangs off of */
88 struct STUFF
*stuff_p
; /* info about the phrase mark */
91 curve_points(mll_p
, stuff_p
, YES
);
95 /* figure out what points are needed for a tie or slur mark */
98 tieslur_points(mll_p
, stuff_p
)
100 struct MAINLL
*mll_p
; /* MAINLL that stuff_p hangs off of */
101 struct STUFF
*stuff_p
; /* info about the phrase mark */
104 /* if slide to/from nowhere in particular, do that */
105 if (nowhere_slide(stuff_p
) == YES
) {
109 curve_points(mll_p
, stuff_p
, NO
);
113 /* determine the 3 points that define a V_shaped bend indicator on the tabnote
114 * staff associated with a tab staff, and put them in the stuff crvlist */
117 bend_points(mll_p
, stuff_p
)
119 struct MAINLL
*mll_p
;
120 struct STUFF
*stuff_p
;
123 struct CRVLIST
*first_point_p
, *last_point_p
; /* the beginning
124 * and end points of the curve */
125 struct CRVLIST
*mid_point_p
; /* middle of the V-shape */
126 struct CRVLIST
*one2discard_p
; /* a point to discard */
127 double midx
, midy
; /* midpoint between the ends */
128 double v_height
; /* V_HEIGHT, or less than
129 * that for narrow V's */
130 double xlen
; /* to help find v_height */
131 double slope
; /* of perpendicular line from
132 * (midx, midy) to the point
133 * of the V, v_height away. */
136 /* first figure everything out as if it were a normal slur */
137 curve_points(mll_p
, stuff_p
, NO
);
139 /* Now make into V-shaped curve.
140 * First throw away the inner points that we had found.
141 * It's a bit unfortunate to do all that work, then throw it
142 * away, but the curve_point() function that finds all the points
143 * also does lots of other good things that we want, so rather than
144 * make it more complicated than it already is by having it know
145 * about bends, we just save the things it did that help us here.
147 first_point_p
= stuff_p
->crvlist_p
;
148 for (last_point_p
= first_point_p
->next
;
149 last_point_p
->next
!= (struct CRVLIST
*) 0; ) {
150 one2discard_p
= last_point_p
;
151 last_point_p
= last_point_p
->next
;
155 /* get a midpoint struct and stitch it into the list */
156 MALLOC(CRVLIST
, mid_point_p
, 1);
157 first_point_p
->next
= mid_point_p
;
158 last_point_p
->prev
= mid_point_p
;
159 mid_point_p
->prev
= first_point_p
;
160 mid_point_p
->next
= last_point_p
;
162 /* find the midpoint of the line between the endpoints */
163 midx
= (last_point_p
->x
+ first_point_p
->x
) / 2.0;
164 midy
= (last_point_p
->y
+ first_point_p
->y
) / 2.0;
166 /* get height. Use V_HEIGHT, except adjust for narrow V's */
167 xlen
= fabs(last_point_p
->x
- first_point_p
->x
);
168 if (xlen
< 2.0 * V_HEIGHT
) {
169 v_height
= 0.35 * V_HEIGHT
;
171 else if (xlen
< 3.5 * V_HEIGHT
) {
172 v_height
= 0.65 * V_HEIGHT
;
178 /* if the y's of the endpoints are equal or nearly so, finding the
179 * midpoint of the V is easy: the x is midx, and the y is midy offset
180 * by v_height in the appropriate direction */
181 if (fabs(last_point_p
->y
- first_point_p
->y
) < 0.001) {
182 mid_point_p
->x
= midx
;
183 mid_point_p
->y
= midy
+ v_height
*
184 (stuff_p
->place
== PL_ABOVE ?
1.0 : -1.0);
188 /* find the slope of the perpendicular */
189 slope
= (first_point_p
->x
- last_point_p
->x
) /
190 (last_point_p
->y
- first_point_p
->y
);
192 /* we want the length of the perpendicular line from (midx, midy)
193 * to the point at the top (or bottom) of the V to be v_height.
194 * Using that line as the hypotenuse of a triangle, we know that
195 * we can find the x and y relative to (midx, midy) by using
196 * Pythagorean x^2 + y^2 = v_height^2. Furthermore, we calculated
197 * the slope of the line earlier, and knowing that slope = y/x,
198 * we now solve 2 equations in 2 unknowns:
199 * x^2 + y^2 = v_height^2
201 * Rearranging the first equation and substituing (slope * x) for y:
202 * x^2 + (slope * x)^2 = v_height^2
204 * (1 + slope^2) * x^2 = v_height^2
205 * x = sqrt( v_height^2 / (1 + slope^2))
206 * Then having found x, solve the second equation for y.
208 * Adjust for being relative to (midx, midy) and for bend direction
209 * and slope direction, and we are done.
211 mid_point_p
->x
= (sqrt((v_height
* v_height
) / (1.0 + (slope
* slope
))))
212 * (first_point_p
->y
> last_point_p
->y ?
1.0 : -1.0)
213 * (stuff_p
->place
== PL_ABOVE ?
1.0 : -1.0);
214 mid_point_p
->y
= (slope
* mid_point_p
->x
) + midy
;
215 mid_point_p
->x
+= midx
;
219 /* determine the 2 points that define a line indicating a slide for a
220 * tab or tabnote staff, and put the points in the stuff crvlist */
223 tabslur_points(mll_p
, stuff_p
)
225 struct MAINLL
*mll_p
;
226 struct STUFF
*stuff_p
;
229 struct CRVLIST
*curvelist_p
;
230 struct GRPSYL
*beggrp_p
;
231 struct GRPSYL
*endgrp_p
;
232 struct NOTE
*begnote_p
;
233 struct NOTE
*endnote_p
;
234 float slant
; /* 0, 1 or -1 to show slant direction */
235 int acc1
, acc2
; /* effective accidentals on the 2 groups,
237 int n
, st
; /* index through notelist and slurtolist */
240 /* if slide to/from nowhere in particular, do that */
241 if (nowhere_slide(stuff_p
) == YES
) {
245 /* find the end note */
246 if (stuff_p
->carryin
== YES
) {
247 /* on carryin, beggrp_p is really the ending group,
248 * and the previous group is the real beggrp_p */
249 endgrp_p
= stuff_p
->beggrp_p
;
250 endnote_p
= stuff_p
->begnote_p
;
251 beggrp_p
= prevgrpsyl(stuff_p
->beggrp_p
, &mll_p
);
253 /* go through all the notes in the previous group,
254 * to find the one that has a slide to the note being
255 * carried into. If there is more than one, use the first
257 for (n
= 0; n
< beggrp_p
->nnotes
; n
++) {
258 for (st
= 0; st
< beggrp_p
->notelist
[n
].nslurto
; st
++) {
259 if (endnote_p
->letter
==
260 beggrp_p
->notelist
[n
].slurtolist
[st
].letter
261 && (is_tab_staff(endgrp_p
->staffno
) == YES
262 || endnote_p
->octave
==
263 beggrp_p
->notelist
[n
].slurtolist
[st
].octave
)) {
264 /* found the one sliding to us */
268 if (st
< beggrp_p
->notelist
[n
].nslurto
) {
269 /* found it, so need to jump out */
273 if (n
== beggrp_p
->nnotes
) {
274 pfatal("can't find note being slid from");
276 begnote_p
= &(beggrp_p
->notelist
[n
]);
279 beggrp_p
= stuff_p
->beggrp_p
;
280 begnote_p
= stuff_p
->begnote_p
;
281 if ((endgrp_p
= nextgrpsyl(stuff_p
->beggrp_p
, &mll_p
))
282 == (struct GRPSYL
*) 0) {
283 pfatal("failed to find next group in tabslur_points");
285 endnote_p
= find_matching_note (endgrp_p
,
286 stuff_p
->begnote_p
->slurtolist
287 [stuff_p
->curveno
].letter
,
288 stuff_p
->begnote_p
->slurtolist
289 [stuff_p
->curveno
].octave
, "slide");
291 if (endnote_p
== (struct NOTE
*) 0) {
292 pfatal("failed to find endnote in tabslur_points");
296 if (is_tab_staff(mll_p
->u
.staff_p
->staffno
) == YES
) {
297 /* figure out whether to slant up or down based on whether
298 * first or second fret is higher */
299 if (begnote_p
->FRETNO
> endnote_p
->FRETNO
) {
307 /* on non-tab staff, usually the line goes to the midpoint of
308 * the note head, so no need to adjust, so set slant to 0 */
311 /* there are two exceptions: first, if both notes have the same
312 * letter/octave, but different accidentals, then we have to
313 * determine the slant based on the accidental. */
314 if (begnote_p
->letter
== endnote_p
->letter
315 && begnote_p
->octave
== endnote_p
->octave
) {
317 /* if the accidental on the begin note is higher than
318 * the accidental on the end note, then it slants
319 * down from left to right, and vice versa. Get the
320 * effective accidental on each group,
321 * accounting for key signature, accidentals earlier
322 * in the measure, etc. */
323 acc1
= eff_acc(beggrp_p
, begnote_p
, mll_p
);
324 acc2
= eff_acc(endgrp_p
, endnote_p
, mll_p
);
326 /* error if the slide is between identical notes */
328 l_ufatal(endgrp_p
->inputfile
,
329 endgrp_p
->inputlineno
,
330 "can't slide to the same note");
332 else if (acc1
> acc2
) {
340 /* second exception: if the slide is carried in, then it needs
341 * to be slanted, so figure out which way */
342 if (stuff_p
->carryin
== YES
) {
344 switch(notecomp( (const void *) begnote_p
,
345 (const void *) endnote_p
)) {
347 switch(notecomp( (char *) begnote_p
, (char *) endnote_p
)) {
356 /* same note, so have to use accidental as
357 * the deciding factor */
358 acc1
= eff_acc(beggrp_p
, begnote_p
, mll_p
);
359 acc2
= eff_acc(endgrp_p
, endnote_p
, mll_p
);
361 /* error if the slide is
362 * between identical notes */
364 l_ufatal(endgrp_p
->inputfile
,
365 endgrp_p
->inputlineno
,
366 "can't slide to the same note");
368 else if (acc1
> acc2
) {
379 /* find beginning point of line */
380 MALLOC(CRVLIST
, curvelist_p
, 1);
381 curvelist_p
->prev
= (struct CRVLIST
*) 0;
382 if (stuff_p
->carryin
== YES
) {
383 /* start a bit west of the end note */
384 curvelist_p
->x
= stuff_p
->beggrp_p
->c
[AX
] +
385 notehorz(stuff_p
->beggrp_p
, stuff_p
->begnote_p
, RW
)
387 curvelist_p
->y
= endnote_p
->c
[RY
] + (slant
* Stepsize
);
390 /* start just beyond east of begin note */
391 curvelist_p
->x
= begnote_p
->c
[AE
] + Stdpad
;
392 curvelist_p
->y
= stuff_p
->begnote_p
->c
[RY
] + (slant
* Stepsize
);
395 /* end point of line */
396 MALLOC(CRVLIST
, curvelist_p
->next
, 1);
397 curvelist_p
->next
->prev
= curvelist_p
;
398 curvelist_p
->next
->next
= (struct CRVLIST
*) 0;
399 if (stuff_p
->carryout
== YES
) {
400 /* extend to near end of score */
401 curvelist_p
->next
->x
= PGWIDTH
- eff_rightmargin(mll_p
) - Stepsize
;
404 /* go to just before west of end note */
405 curvelist_p
->next
->x
= endgrp_p
->c
[AX
] +
406 notehorz(endgrp_p
, endnote_p
, RW
) - Stdpad
;
408 curvelist_p
->next
->y
= endnote_p
->c
[RY
] - (slant
* Stepsize
);
410 /* attach to stuff */
411 stuff_p
->crvlist_p
= curvelist_p
;
413 /* place doesn't really make sense, so set arbitrarily */
414 stuff_p
->place
= PL_ABOVE
;
418 /* if the slide for given tabslur stuff is to/from nowhere in particular,
419 * then handle that here and return YES. Otherwise return NO. */
422 nowhere_slide(stuff_p
)
424 struct STUFF
*stuff_p
;
427 double boundary
; /* east or west boundary of note, with
428 * the slide included */
429 double adjust
= 0.0; /* to move the slanted line slightly when
430 * there is a note on the other side of
431 * the stem that is in the way. */
435 float slidexlen
; /* SLIDEXLEN * Staffscale */
438 if (stuff_p
->curveno
< 0) {
442 if (stuff_p
->begnote_p
->nslurto
== 0) {
446 /* find which note it is in the chord, so check later for possible
447 * collisions between the slide and a neighboring note */
448 gs_p
= stuff_p
->beggrp_p
;
449 note_p
= stuff_p
->begnote_p
;
450 for (n
= 0; n
< gs_p
->nnotes
; n
++) {
451 if ( &(gs_p
->notelist
[n
]) == note_p
) {
455 if (n
== gs_p
->nnotes
) {
456 pfatal("couldn't find note in chord for slide");
459 slidexlen
= SLIDEXLEN
* Staffscale
;
461 /* for each type, find the outer boundary of the note with the
462 * nowhere slide included and draw a line from there towards the
463 * note, slanted the appropriate direction */
464 switch (stuff_p
->begnote_p
->slurtolist
[stuff_p
->curveno
].octave
) {
467 boundary
= stuff_p
->beggrp_p
->c
[AX
] +
468 notehorz(stuff_p
->beggrp_p
, stuff_p
->begnote_p
, RW
);
469 /* If there is a note one stepsize below this note, and it's
470 * to the left of the stem while the target note is on the
471 * right side, move the slide up a
472 * tiny bit so it doesn't get swallowed up in that other note
473 * and/or a slide coming into it.
474 * If we're sliding into the middle of a cluster with
475 * wrong-side notes both above and below the target note, it
476 * will still get somewhat swallowed, but that's unlikely to
477 * happen very often, and if it does, this is still about the
478 * best we can manage in that case. */
480 if (n
< gs_p
->nnotes
&& gs_p
->notelist
[n
].stepsup
481 == note_p
->stepsup
- 1 &&
482 gs_p
->notelist
[n
].c
[AX
] < note_p
->c
[AX
]) {
486 boundary
, stuff_p
->begnote_p
->c
[RY
] - Stepsize
+ adjust
,
487 boundary
+ slidexlen
, stuff_p
->begnote_p
->c
[RY
] + adjust
);
491 boundary
= stuff_p
->beggrp_p
->c
[AX
] +
492 notehorz(stuff_p
->beggrp_p
, stuff_p
->begnote_p
, RW
);
493 /* if there is a note just above that we might
494 * collide with, adjust to dodge it. */
496 if (n
>= 0 && gs_p
->notelist
[n
].stepsup
497 == note_p
->stepsup
+ 1 &&
498 gs_p
->notelist
[n
].c
[AX
] < note_p
->c
[AX
]) {
502 boundary
, stuff_p
->begnote_p
->c
[RY
] + Stepsize
- adjust
,
503 boundary
+ slidexlen
, stuff_p
->begnote_p
->c
[RY
] - adjust
);
507 boundary
= stuff_p
->beggrp_p
->c
[AX
] +
508 notehorz(stuff_p
->beggrp_p
, stuff_p
->begnote_p
, RE
);
509 /* If note just above this one that we might collide with,
512 if (n
>= 0 && gs_p
->notelist
[n
].stepsup
513 == note_p
->stepsup
+ 1 &&
514 gs_p
->notelist
[n
].c
[AX
] > note_p
->c
[AX
]) {
518 boundary
- slidexlen
, stuff_p
->begnote_p
->c
[RY
] - adjust
,
519 boundary
, stuff_p
->begnote_p
->c
[RY
] + Stepsize
- adjust
);
523 boundary
= stuff_p
->beggrp_p
->c
[AX
] +
524 notehorz(stuff_p
->beggrp_p
, stuff_p
->begnote_p
, RE
);
525 /* If note below we might collide with, dodge it */
527 if (n
< gs_p
->nnotes
&& gs_p
->notelist
[n
].stepsup
528 == note_p
->stepsup
- 1 &&
529 gs_p
->notelist
[n
].c
[AX
] > note_p
->c
[AX
]) {
533 boundary
- slidexlen
, stuff_p
->begnote_p
->c
[RY
] + adjust
,
534 boundary
, stuff_p
->begnote_p
->c
[RY
] - Stepsize
+ adjust
);
543 /* make a CRVLIST with the 2 given points and put it in the given stuff */
546 do_nowhere(stuff_p
, x1
, y1
, x2
, y2
)
548 struct STUFF
*stuff_p
;
549 double x1
, y1
, x2
, y2
;
552 MALLOC(CRVLIST
, stuff_p
->crvlist_p
, 1);
553 stuff_p
->crvlist_p
->x
= x1
;
554 stuff_p
->crvlist_p
->y
= y1
;
555 MALLOC(CRVLIST
, stuff_p
->crvlist_p
->next
, 1);
556 stuff_p
->crvlist_p
->next
->x
= x2
;
557 stuff_p
->crvlist_p
->next
->y
= y2
;
559 stuff_p
->crvlist_p
->prev
= stuff_p
->crvlist_p
->next
->next
560 = (struct CRVLIST
*) 0;
561 stuff_p
->crvlist_p
->next
->prev
= stuff_p
->crvlist_p
;
563 /* place is not really relevant, but put something in it */
564 stuff_p
->place
= PL_ABOVE
;
568 /* Figure out what points are needed for a curve, either a phrase mark
569 * or a tie/slur, or a bend.
570 * First it figures out where the endpoints should be,
571 * then finds a curve that will be beyond all the groups that it covers.
575 curve_points(mll_p
, stuff_p
, is_phrase
)
577 struct MAINLL
*mll_p
; /* MAINLL that stuff_p hangs off of */
578 struct STUFF
*stuff_p
; /* info about the phrase mark or tie/slur */
579 int is_phrase
; /* YES if phrase, NO if tie or slur */
582 struct GRPSYL
*begin_gs_p
; /* curve starts on this group */
583 struct GRPSYL
*end_gs_p
; /* curve ends on this group */
584 struct NOTE
*begnote_p
; /* first note for tie/slur */
585 struct NOTE
*endnote_p
= 0; /* last note of tie/slur */
586 int place
; /* bend PL_ABOVE or PL_BELOW */
587 int side
; /* RN or RS */
588 int side_adj
; /* AN or AS. This field is used to
589 * adjust for nested phrase marks */
590 double bulgeval
; /* bulge factor of curve */
591 int try; /* count of tries to get a good curve */
592 int found_good
; /* YES if found a good-looking curve */
593 struct TRYBULGE tb
; /* Info for try_bulge() */
594 struct TRYBULGE
*try_p
; /* = &tb */
595 float sign
; /* based on if curve is up or down */
596 struct CRVLIST
*curvelist_p
; /* beginning of curve */
597 struct CRVLIST
*endlist_p
; /* last point of curve */
598 struct CRVLIST
*new_p
; /* point to add to list of points */
599 struct MAINLL
*bar_mll_p
= 0; /* to find bar or pseudo bar */
600 float length
; /* length of curve */
601 float ylen
; /* length of segment in y direction before
603 float y_adj
= 0.0, y2_adj
= 0.0;/* if moved because was an end note */
604 char *name
; /* "phrase" or "tie/slur" */
605 float sintheta
, costheta
;/* for rotating */
608 debug(32, "curve_points lineno %d", stuff_p
->inputlineno
);
610 /* get short names to groups and notes we'll use a lot */
611 begin_gs_p
= stuff_p
->beggrp_p
;
612 end_gs_p
= stuff_p
->endgrp_p
;
613 begnote_p
= stuff_p
->begnote_p
;
615 /* figure out what string ("phrase" or "tie/slur") to use for error
616 * messages and make sure begin group is not null */
617 if (is_phrase
== YES
) {
619 if ( (begin_gs_p
== (struct GRPSYL
*) 0)
620 || (end_gs_p
== (struct GRPSYL
*) 0) ) {
621 pfatal("no group associated with phrase");
628 if (begin_gs_p
== (struct GRPSYL
*) 0) {
629 pfatal("no group associated with tie/slur");
631 /* figure out which direction to bend the tie/slur */
632 if (stuff_p
->carryin
== YES
) {
637 /* Need to base bend direction on the
638 * group/note/curve that was the carryout,
639 * otherwise the carryin and carryout could have
640 * different bend directions.
641 * We also need the costuff_p to get
642 * any user override of bend direction.
644 * Find the MAINLL pointing to the STAFF that
645 * should contain the costuff. Use prevgrpsyl,
646 * since it knows how to deal with endings,
647 * but we're really interested in the MAINLL
648 * pointing to the GRPSYL
649 * rather than the GRPSYL itself.
652 /* First make sure we have the first group
654 for (g_p
= begin_gs_p
; g_p
->prev
!= 0; g_p
= g_p
->prev
) {
658 /* Now find the MAINLL pointing to the prev meas */
660 (void) prevgrpsyl(g_p
, &m_p
);
661 if (m_p
== 0 || m_p
->str
!= S_STAFF
) {
662 pfatal("failed to find costaff_p's mainll");
665 /* Locate the costuff. We could just use
666 * stuff_p->costuff_p, but by searching for it here,
667 * we double check that we really found the right
668 * MAINLL, and can pfatal if not. */
669 for (st_p
= m_p
->u
.staff_p
->stuff_p
; st_p
!= 0;
671 if (st_p
== stuff_p
->costuff_p
) {
676 pfatal("failed to find costaff_p from mainll");
679 indx
= st_p
->begnote_p
- &(st_p
->beggrp_p
->notelist
[0]);
680 stuff_p
->place
= (bulge_direction(m_p
, st_p
->beggrp_p
,
681 indx
, st_p
->curveno
) == UP
682 ? PL_ABOVE
: PL_BELOW
);
685 indx
= begnote_p
- &(begin_gs_p
->notelist
[0]);
686 stuff_p
->place
= (bulge_direction(mll_p
, begin_gs_p
,
687 indx
, stuff_p
->curveno
) == UP
688 ? PL_ABOVE
: PL_BELOW
);
692 place
= stuff_p
->place
;
694 /* determine whether to use north or south of groups, and what sign to
695 * use to get the bends in the correct direction */
696 if (place
== PL_ABOVE
) {
707 /* set up the beginning coord */
708 MALLOC(CRVLIST
, curvelist_p
, 1);
709 curvelist_p
->prev
= (struct CRVLIST
*) 0;
710 if (is_phrase
== YES
) {
711 /* Start slightly to east of center, so that if another
712 * curves ends on this group, they won't quite touch */
713 curvelist_p
->x
= begin_gs_p
->c
[AX
] + XOFFSET4CURVE
;
714 if (begin_gs_p
->grpcont
!= GC_SPACE
) {
715 curvelist_p
->y
= begin_gs_p
->c
[side
]
716 + eff_tupext(begin_gs_p
, mll_p
->u
.staff_p
, place
)
717 + (sign
* 2.0 * Stdpad
);
718 /* If there is something in [side_adj] there
719 * was another phrase on this group. But if that phrase
720 * ended on this group, it can be ignored. */
721 if (begin_gs_p
->c
[side_adj
] != 0.0 &&
722 (begin_gs_p
->phraseside
& EAST_SIDE
)) {
723 curvelist_p
->y
+= begin_gs_p
->c
[side_adj
];
727 /* bizarre case. first group is a space.
728 * Use 1 step from top or bottom of staff for y coord */
729 curvelist_p
->y
= sign
* (1 + halfstaffhi(begin_gs_p
->staffno
));
733 else { /* is tie or slur */
735 curvelist_p
->y
= begnote_p
->c
[RY
];
738 /* if on the "end" note of a group,
739 * the curve can probably be moved
740 * to the x of the note instead of the edge of the group.
741 * We assume it can if the curve bends away
742 * from the stem and there are no "with"
743 * list items on the group. If there is a with list, move
744 * a little bit, but not enough to hit with items */
745 if (begin_gs_p
->stemdir
== UP
&& place
== PL_BELOW
746 && begnote_p
== &(begin_gs_p
->notelist
747 [begin_gs_p
->nnotes
- 1])) {
748 if (begin_gs_p
->nwith
== 0 || begin_gs_p
->normwith
== NO
) {
749 curvelist_p
->x
= begnote_p
->c
[AX
]
751 y_adj
= (Stepsize
* (begnote_p
->notesize
752 == GS_NORMAL ?
1.7 : 1.2));
753 curvelist_p
->y
-= y_adj
;
756 curvelist_p
->x
= begnote_p
->c
[AE
];
757 y_adj
= (Stepsize
* (begnote_p
->notesize
758 == GS_NORMAL ?
1.2 : 0.9));
759 curvelist_p
->y
-= y_adj
;
762 else if (begin_gs_p
->stemdir
== DOWN
&& place
== PL_ABOVE
763 && begnote_p
== &(begin_gs_p
->notelist
[0])) {
764 if (begin_gs_p
->nwith
== 0
765 || begin_gs_p
->normwith
== NO
) {
766 curvelist_p
->x
= begnote_p
->c
[AX
]
768 y_adj
= (Stepsize
* (begnote_p
->notesize
769 == GS_NORMAL ?
1.7 : 1.2));
770 curvelist_p
->y
+= y_adj
;
773 curvelist_p
->x
= begnote_p
->c
[AE
];
774 y_adj
= (Stepsize
* (begnote_p
->notesize
775 == GS_NORMAL ?
1.2 : 0.9));
776 curvelist_p
->y
+= y_adj
;
780 /* whole notes and longer don't really have a stem, so top
781 * note of "stem up" can be moved. Stemless grace notes also
782 * don't have a stem, so the same logic applies. */
783 else if ( (begin_gs_p
->basictime
< 2
784 || (begin_gs_p
->grpvalue
== GV_ZERO
785 && begin_gs_p
->basictime
< 8))
786 && begin_gs_p
->stemdir
== UP
787 && place
== PL_ABOVE
&&
788 begnote_p
== &(begin_gs_p
->notelist
[0])) {
789 if (begin_gs_p
->nwith
== 0
790 || begin_gs_p
->normwith
== YES
) {
791 curvelist_p
->x
= begnote_p
->c
[AX
] + Stdpad
;
792 y_adj
= (Stepsize
* (begnote_p
->notesize
793 == GS_NORMAL ?
1.7 : 1.2));
794 curvelist_p
->y
+= y_adj
;
797 curvelist_p
->x
= begnote_p
->c
[AE
];
798 y_adj
= (Stepsize
* (begnote_p
->notesize
799 == GS_NORMAL ?
1.2 : 0.9));
800 curvelist_p
->y
+= y_adj
;
804 /* can also be moved if bottom note of stem-down group */
805 else if (begin_gs_p
->stemdir
== DOWN
&& place
== PL_BELOW
806 && begnote_p
== &(begin_gs_p
->notelist
807 [begin_gs_p
->nnotes
- 1]) &&
808 stuff_p
->carryin
== NO
) {
809 if (begin_gs_p
->basictime
< 2 && begin_gs_p
->nwith
> 0
810 && begin_gs_p
->normwith
== NO
) {
811 curvelist_p
->x
= begin_gs_p
->c
[AE
];
812 y_adj
= (Stepsize
* (begnote_p
->notesize
813 == GS_NORMAL ?
1.2 : 0.9));
814 curvelist_p
->y
-= y_adj
;
817 curvelist_p
->x
= begin_gs_p
->c
[AX
];
818 y_adj
= (Stepsize
* (begnote_p
->notesize
819 == GS_NORMAL ?
1.7 : 1.2));
820 curvelist_p
->y
-= y_adj
;
824 curvelist_p
->x
= begin_gs_p
->c
[AX
] +
825 notehorz(begin_gs_p
, begnote_p
, RE
) +
829 /* If two notes are a stepsize apart and the curve from the
830 * west note is bending towards the east note,
831 * then the x should be moved east a little.
832 * First case: this isn't the top note, but the note just
833 * above is 1 stepsize away and on the east side, and the
834 * curve is going up and it's not a carryin. */
835 if (begnote_p
!= &(begin_gs_p
->notelist
[0]) &&
836 begnote_p
->stepsup
==
837 begnote_p
[-1].stepsup
- 1 &&
838 begnote_p
->c
[RX
] < begnote_p
[-1].c
[RX
] &&
840 stuff_p
->carryin
== NO
) {
841 curvelist_p
->x
+= 1.5 * Stepsize
;
843 /* Second case: not bottom note, note just
844 * below is one step away and on the east side, the curve
845 * is going down, and it's not a carryin. */
846 else if (begnote_p
!= &(begin_gs_p
->notelist
[begin_gs_p
->nnotes
-1]) &&
847 begnote_p
->stepsup
==
848 begnote_p
[1].stepsup
+ 1 &&
849 begnote_p
->c
[RX
] < begnote_p
[1].c
[RX
] &&
851 stuff_p
->carryin
== NO
) {
852 curvelist_p
->x
+= 1.5 * Stepsize
;
857 /* if carried over from previous score, start a bit farther left */
858 if (stuff_p
->carryin
== YES
) {
860 /* find the pseudo bar and set x to that */
861 for (bar_mll_p
= mll_p
->prev
;
862 bar_mll_p
!= (struct MAINLL
*) 0;
863 bar_mll_p
= bar_mll_p
->prev
) {
864 if (bar_mll_p
->str
== S_CLEFSIG
) {
865 if (bar_mll_p
->u
.clefsig_p
->bar_p
866 == (struct BAR
*) 0) {
867 /* carryin to an ending */
871 bar_mll_p
->u
.clefsig_p
->bar_p
->c
[AE
]
872 - (TIESLURPAD
* Staffscale
);
874 /* Long notes (wholes, etc) generally get
875 * more space on their left than short notes,
876 * so a curve carried in to a long note
877 * may look overly long, especially if other
878 * scores on the same page have carryins
879 * to short notes. So limit carryin curve
880 * length to 5 stepsizes.
882 if (begin_gs_p
->c
[AW
] - curvelist_p
->x
> 5.0 * Stepsize
) {
883 curvelist_p
->x
= begin_gs_p
->c
[AW
]
888 else if (bar_mll_p
->str
== S_BAR
) {
889 /* carryin to an ending */
890 curvelist_p
->x
= begin_gs_p
->c
[AW
];
895 if (bar_mll_p
== (struct MAINLL
*) 0) {
896 pfatal("missing CELFSIG when carrying over %s mark",
901 /* set up ending coord */
902 MALLOC(CRVLIST
, endlist_p
, 1);
903 if (is_phrase
== YES
) {
904 /* End slightly to west of group center, so that another
905 * curve can start on this group (if needed) with
906 * touching this curve. */
907 endlist_p
->x
= end_gs_p
->c
[AX
] - XOFFSET4CURVE
;
908 if (end_gs_p
->grpcont
!= GC_SPACE
) {
909 endlist_p
->y
= end_gs_p
->c
[side
]
910 + eff_tupext(end_gs_p
, mll_p
->u
.staff_p
, place
)
911 + (sign
* 2.0 * Stdpad
);
912 /* Add in space for any relevant nested phrases */
913 if (end_gs_p
->c
[side_adj
] != 0.0 &&
914 (end_gs_p
->phraseside
& WEST_SIDE
)) {
915 endlist_p
->y
+= end_gs_p
->c
[side_adj
];
919 /* bizarre case. last group is a space. Use 1 stepsize
920 * from top or bottom of staff for y coord */
921 endlist_p
->y
= sign
* (1 + halfstaffhi(begin_gs_p
->staffno
));
925 if (stuff_p
->carryin
== YES
) {
926 /* in case of carryin, the "begin" group is actually
927 * the ending group, so set the end group, and
928 * adjust the beginning y */
929 endlist_p
->x
= begin_gs_p
->c
[AW
];
931 /* adjust things carried into endings to account for
932 * the padding that was added */
933 if (bar_mll_p
->str
== S_BAR
) {
934 endlist_p
->x
+= TIESLURPAD
* Staffscale
;
937 endlist_p
->y
= curvelist_p
->y
;
938 end_gs_p
= begin_gs_p
;
940 /* if end note, adjust */
941 if (place
== PL_ABOVE
&& begnote_p
942 == &(begin_gs_p
->notelist
[0])) {
943 endlist_p
->x
= begnote_p
->c
[AX
];
944 if ((begin_gs_p
->basictime
> 1) &&
945 (begin_gs_p
->stemdir
== UP
)) {
946 endlist_p
->y
+= Stepsize
;
947 curvelist_p
->y
+= Stepsize
;
950 else if (place
== PL_BELOW
&& begnote_p
==
951 &(begin_gs_p
->notelist
952 [begin_gs_p
->nnotes
- 1])
953 && (begin_gs_p
->stemdir
== UP
954 || begin_gs_p
->basictime
< 2)) {
955 endlist_p
->x
= begnote_p
->c
[AX
];
956 if ((begin_gs_p
->basictime
< 2) &&
957 (begin_gs_p
->stemdir
== DOWN
)) {
958 endlist_p
->y
-= Stepsize
;
959 curvelist_p
->y
-= Stepsize
;
965 end_gs_p
= find_next_group (mll_p
, begin_gs_p
,
966 (stuff_p
->curveno
== -1 ?
"tie" : "slur"));
967 if (stuff_p
->curveno
== -1) {
969 endnote_p
= find_matching_note (end_gs_p
,
971 begnote_p
->octave
, "tie");
974 if (IS_NOWHERE(begnote_p
->slurtolist
975 [stuff_p
->curveno
].octave
)) {
976 pfatal("curve_points called on slide to nowhere");
979 endnote_p
= find_matching_note (end_gs_p
,
980 begnote_p
->slurtolist
981 [stuff_p
->curveno
].letter
,
982 begnote_p
->slurtolist
983 [stuff_p
->curveno
].octave
,
987 endlist_p
->y
= endnote_p
->c
[RY
];
991 /* move if below curve and bottom note with stem up */
992 if (end_gs_p
->stemdir
== UP
&& place
== PL_BELOW
993 && endnote_p
== &(end_gs_p
->notelist
994 [end_gs_p
->nnotes
- 1])) {
995 if (end_gs_p
->nwith
== 0
996 || end_gs_p
->normwith
== NO
) {
997 endlist_p
->x
= endnote_p
->c
[AX
]
1000 (endnote_p
->notesize
1001 == GS_NORMAL ?
1.7 : 1.2));
1002 endlist_p
->y
-= y2_adj
;
1005 endlist_p
->x
= endnote_p
->c
[AW
];
1006 y2_adj
= (Stepsize
*
1007 (endnote_p
->notesize
1008 == GS_NORMAL ?
1.2 : 0.9));
1009 endlist_p
->y
-= y2_adj
;
1013 /* move if above and top note with stem down */
1014 else if (end_gs_p
->stemdir
== DOWN
&& place
== PL_ABOVE
1015 && endnote_p
== &(end_gs_p
->notelist
[0])) {
1016 if (end_gs_p
->nwith
== 0
1017 || end_gs_p
->normwith
== NO
) {
1018 endlist_p
->x
= endnote_p
->c
[AX
]
1020 y2_adj
= (Stepsize
*
1021 (endnote_p
->notesize
1022 == GS_NORMAL ?
1.7 : 1.2));
1023 endlist_p
->y
+= y2_adj
;
1026 endlist_p
->x
= endnote_p
->c
[AW
];
1027 y2_adj
= (Stepsize
*
1028 (endnote_p
->notesize
1029 == GS_NORMAL ?
1.2 : 0.9));
1030 endlist_p
->y
+= y2_adj
;
1034 /* whole and longer don't have stem, so end note where
1035 * a stem would be (if there were one) can be moved */
1036 else if (end_gs_p
->basictime
< 2 &&
1037 end_gs_p
->stemdir
== DOWN
1038 && place
== PL_BELOW
1039 && endnote_p
== &(end_gs_p
->notelist
1040 [end_gs_p
->nnotes
- 1])) {
1041 if (end_gs_p
->nwith
== 0
1042 || end_gs_p
->normwith
== YES
) {
1043 endlist_p
->x
= endnote_p
->c
[AX
]
1045 y2_adj
= (Stepsize
*
1046 (endnote_p
->notesize
1047 == GS_NORMAL ?
1.7 : 1.2));
1048 endlist_p
->y
-= y2_adj
;
1051 endlist_p
->x
= endnote_p
->c
[AW
];
1052 y2_adj
= (Stepsize
*
1053 (endnote_p
->notesize
1054 == GS_NORMAL ?
1.2 : 0.9));
1055 endlist_p
->y
-= y2_adj
;
1059 /* move if above and top note of stem up */
1060 else if (end_gs_p
->stemdir
== UP
&& place
== PL_ABOVE
1062 &(end_gs_p
->notelist
[0]) ) {
1063 endlist_p
->x
= end_gs_p
->c
[AX
];
1064 y2_adj
= (Stepsize
* (endnote_p
->notesize
1065 == GS_NORMAL ?
1.7 : 1.2));
1066 endlist_p
->y
+= y2_adj
;
1068 /* if tied from note is also the top of its
1069 * group, level the tie/slur */
1070 if (begin_gs_p
->stemdir
== UP
&&
1072 &(begin_gs_p
->notelist
[0]) &&
1073 begin_gs_p
->basictime
> 1 ) {
1074 curvelist_p
->y
+= (Stepsize
*
1075 (begnote_p
->notesize
1076 == GS_NORMAL ?
1.7 : 1.2));
1079 else if (begin_gs_p
->grpvalue
== GV_ZERO
) {
1080 /* grace note to main note, can't use the west
1081 * of the end group because that would include
1082 * the grace note. */
1083 endlist_p
->x
= endnote_p
->c
[AX
] +
1084 notehorz(end_gs_p
, endnote_p
, RW
);
1087 endlist_p
->x
= tieslurx(end_gs_p
, endnote_p
,
1088 stuff_p
->place
) - (2.0 * Stdpad
);
1091 /* if note tied from is bottom of group with stem down,
1092 * level the tie/slur */
1093 if (end_gs_p
->stemdir
== DOWN
&& place
== PL_BELOW
1094 && endnote_p
== &(end_gs_p
->notelist
1095 [end_gs_p
->nnotes
- 1]) &&
1096 begin_gs_p
->stemdir
== DOWN
&&
1097 begnote_p
== &(begin_gs_p
->notelist
1098 [begin_gs_p
->nnotes
- 1]) &&
1099 end_gs_p
->basictime
> 1 ) {
1100 endlist_p
->y
-= (Stepsize
*
1101 (begnote_p
->notesize
1102 == GS_NORMAL ?
1.7 : 1.2));
1105 /* if beginning of curve was adjusted and this is
1106 * an inner note, but there is room on the relevant
1107 * side, and this is a tie, then adjust this end's y
1108 * to level the curve */
1109 else if (y_adj
!= 0.0 && stuff_p
->curveno
== -1) {
1110 endlist_p
->y
+= inner_adj(end_gs_p
, endnote_p
,
1114 /* level beginning if the note in the previous
1115 * chord was the same note but wasn't the top,
1116 * but the next note is more than a stepsize
1118 if (y2_adj
!= 0.0 && stuff_p
->curveno
== -1) {
1119 curvelist_p
->y
+= inner_adj(begin_gs_p
,
1120 begnote_p
, y2_adj
, place
);
1125 /* one final adjustment. If the stem of first group is up and stem
1126 * of second group is down, and the notes being tied/slurred are both
1127 * the tops notes if the place is above or both bottom notes if the
1128 * place is below, then move the y coord on the side that wasn't
1129 * already moved, to level the curve. Do only if the note is shorter
1130 * than a whole note, because longer notes were already moved because
1131 * they had no stem. */
1132 if (is_phrase
== NO
&& begin_gs_p
->stemdir
== UP
1133 && end_gs_p
!= (struct GRPSYL
*) 0
1134 && end_gs_p
->stemdir
== DOWN
) {
1135 if (place
== PL_ABOVE
&& begnote_p
==
1136 &(begin_gs_p
->notelist
[0])
1137 && endnote_p
== &(end_gs_p
->notelist
[0])
1138 && begin_gs_p
->basictime
> 1) {
1139 curvelist_p
->y
+= (Stepsize
* (begnote_p
->notesize
1140 == GS_NORMAL ?
1.7 : 1.2));
1142 else if (place
== PL_BELOW
&& begnote_p
==
1143 &(begin_gs_p
->notelist
[begin_gs_p
->nnotes
- 1])
1145 &(end_gs_p
->notelist
[end_gs_p
->nnotes
- 1])
1146 && end_gs_p
->basictime
> 1) {
1147 endlist_p
->y
-= (Stepsize
* (endnote_p
->notesize
1148 == GS_NORMAL ?
1.7 : 1.2));
1152 endlist_p
->next
= (struct CRVLIST
*) 0;
1153 /* no need to set other links now because we will be added other nodes
1154 * in between in a moment anyway */
1156 /* if carrying over, extend x to margin */
1157 if (stuff_p
->carryout
) {
1158 endlist_p
->x
= PGWIDTH
- eff_rightmargin(mll_p
);
1161 /* find length of curve by Pythagorean */
1162 length
= sqrt(SQUARED(endlist_p
->x
- curvelist_p
->x
)
1163 + SQUARED(endlist_p
->y
- curvelist_p
->y
));
1165 /* Find y length for creating bulge in the curve.
1166 * Make bigger bend if longer curve, but not too big or too small.
1169 if (ylen
> 2.2 * Stepsize
) {
1170 ylen
= 2.2 * Stepsize
;
1172 else if (ylen
< (Stepsize
* 0.75)) {
1173 ylen
= Stepsize
* 0.75;
1177 /* we figure out curve as if endpoints were on the x axis, then adjust
1178 * with the proper sin and cos factors to get them where they really
1180 sintheta
= (endlist_p
->y
- curvelist_p
->y
) / length
;
1181 costheta
= (endlist_p
->x
- curvelist_p
->x
) / length
;
1183 /* set up node for another point on curve */
1184 MALLOC(CRVLIST
, new_p
, 1);
1185 new_p
->prev
= curvelist_p
;
1186 new_p
->next
= endlist_p
;
1187 curvelist_p
->next
= new_p
;
1188 endlist_p
->prev
= new_p
;
1190 if (stuff_p
->carryout
== YES
) {
1191 if (is_phrase
== YES
) {
1192 endlist_p
->y
+= ylen
/ 2.0;
1195 end_gs_p
= begin_gs_p
;
1199 /* First try a single point in the middle. Try bigger bulge
1200 * value if some groups stick out, up to a maximum. */
1202 tb
.begin_gs_p
= begin_gs_p
;
1203 tb
.end_gs_p
= end_gs_p
;
1205 tb
.curvelist_p
= curvelist_p
;
1206 tb
.endlist_p
= endlist_p
;
1207 tb
.xlen
= length
/ 2.0;
1209 tb
.sintheta
= sintheta
;
1210 tb
.costheta
= costheta
;
1211 tb
.minbulge
= MINBULGE
;
1212 tb
.maxbulge
= MAXBULGE
;
1214 if ((bulgeval
= try_bulge(try_p
)) < MAXBULGE
) {
1215 /* This curve works. Go with it */
1216 if (bulgeval
== MINBULGE
) {
1217 /* The very first try worked with nothing in the way,
1218 * so may be safe to try to
1219 * beautify any really steep curves.
1220 * So try to redo and see if still okay.
1221 * If not, put back the original.
1223 double save_x
, save_y
;
1224 save_x
= curvelist_p
->next
->x
;
1225 save_y
= curvelist_p
->next
->y
;
1226 redo_steep(curvelist_p
, endlist_p
, place
);
1227 if (stick_out(try_p
) > 0.0) {
1228 curvelist_p
->next
->x
= save_x
;
1229 curvelist_p
->next
->y
= save_y
;
1232 /* adjust group boundaries to include the curve */
1233 final_touches(mll_p
, begin_gs_p
, end_gs_p
, curvelist_p
, place
);
1235 /* attach the curve to the stuff */
1236 stuff_p
->crvlist_p
= curvelist_p
;
1240 /* Using a single inner point didn't give a good curve.
1241 * So we'll try two inner points. Add another point to the curve. */
1242 MALLOC(CRVLIST
, new_p
, 1);
1243 new_p
->prev
= endlist_p
->prev
;
1244 new_p
->next
= endlist_p
;
1245 new_p
->prev
->next
= new_p
;
1246 endlist_p
->prev
= new_p
;
1248 /* We now have three segments, each 1/3 of total length */
1249 tb
.xlen
= length
/ 3.0;
1251 /* We're a little more desperate, so allow more bulge */
1252 tb
.minbulge
= MIN2BULGE
;
1253 tb
.maxbulge
= MAX2BULGE
;
1255 if ((bulgeval
= try_bulge(try_p
)) < MAXBULGE
) {
1256 /* This curve works. Go with it */
1257 final_touches(mll_p
, begin_gs_p
, end_gs_p
, curvelist_p
, place
);
1259 /* attach the curve to the stuff */
1260 stuff_p
->crvlist_p
= curvelist_p
;
1264 /* Really getting desperate now, so allow even more bulge */
1265 tb
.minbulge
= MIN3BULGE
;
1266 tb
.maxbulge
= MAX3BULGE
;
1268 /* Just adjusting bulge didn't work,
1269 * so we try repeatedly moving the ends slightly
1270 * and trying again until something works.
1271 * Worst case should be something like an above curve encompassing c0
1272 * to b9 back to c0, with a stem up on the b9. That would be about 80
1273 * stepsizes. But if an end is a cross-staff stem group completely
1274 * on the other staff, and if that other staff is ridiculously
1275 * far away because of very tall STUFF, even 100 iterations
1276 * of moving by a Stepsize sometimes isn't enough.
1277 * So we'll try 200 times before giving up with a pfatal.
1280 for (try = 0; try < 200; try++) {
1281 double mvbegin
, mvend
, mvboth
;
1282 int leftcount
, rightcount
;
1284 /* Try moving each end individually and both together,
1285 * then try to go with whatever gave the best results
1286 * with the least movement.
1289 /* try with just begin point moved */
1290 curvelist_p
->y
+= Stepsize
* sign
;
1291 mvbegin
= try_bulge(try_p
);
1293 /* try with both endpoints moved */
1294 endlist_p
->y
+= Stepsize
* sign
;
1295 mvboth
= try_bulge(try_p
);
1296 leftcount
= tb
.leftcount
;
1297 rightcount
= tb
.rightcount
;
1299 /* try with just end point moved */
1300 curvelist_p
->y
-= Stepsize
* sign
;
1301 mvend
= try_bulge(try_p
);
1303 /* See which of the three attempts seemed best */
1304 if ( (mvend
< mvbegin
&& mvend
< mvboth
)
1305 || (try < 5 && leftcount
== 0 && rightcount
> 0) ) {
1306 /* moving just the end was best */
1307 if (mvend
< MAX3BULGE
) {
1312 else if ( (mvbegin
< mvend
&& mvbegin
< mvboth
)
1313 || (try < 5 && leftcount
> 0 && rightcount
== 0) ) {
1314 /* moving just the beginning was best */
1315 curvelist_p
->y
+= Stepsize
* sign
;
1316 endlist_p
->y
-= Stepsize
* sign
;
1317 if (mvbegin
< MAX3BULGE
) {
1323 /* move both ends */
1324 curvelist_p
->y
+= Stepsize
* sign
;
1325 if (mvboth
< MAX3BULGE
) {
1332 if (found_good
== YES
) {
1333 /* Call try_bulge again to set the inner points (the one
1334 * we chose might not be the last one we tried. */
1335 (void) try_bulge(try_p
);
1336 final_touches(mll_p
, begin_gs_p
, end_gs_p
, curvelist_p
, place
);
1338 /* attach the curve to the stuff */
1339 stuff_p
->crvlist_p
= curvelist_p
;
1343 pfatal("unable to find a usable curve");
1348 * Returns the smallest bulge factor that worked, or a value >= maxbulge if
1349 * nothing worked. The more the return value exceeds maxbulge, the worse
1350 * the amount of "stick out." The curvelist_p should point to a curve with
1357 struct TRYBULGE
*info_p
; /* points to all the info this func needs */
1360 struct CRVLIST
*mid_p
; /* interior point of curve */
1361 struct CRVLIST
*mid2_p
; /* second inner point, if any */
1362 double bulge_factor
; /* how much to bulge */
1363 double amount
= 0.0; /* amount of stick out */
1366 /* Get pointer to the midpoint(s) */
1367 mid_p
= info_p
->curvelist_p
->next
;
1368 if (mid_p
->next
!= info_p
->endlist_p
) {
1369 mid2_p
= mid_p
->next
;
1375 /* Keep trying bigger bulge until we find one that clears all the
1376 * groups or until the specified maximum is reached. */
1377 for (bulge_factor
= info_p
->minbulge
; bulge_factor
< info_p
->maxbulge
;
1378 bulge_factor
+= 0.25) {
1380 /* find (x,y) values for midpoint(s) taking the rotation
1381 * from horizontal into account. */
1382 mid_p
->x
= info_p
->curvelist_p
->x
1383 + (info_p
->xlen
* info_p
->costheta
)
1384 - (bulge_factor
* info_p
->ylen
* info_p
->sintheta
);
1385 mid_p
->y
= info_p
->curvelist_p
->y
1386 + (bulge_factor
* info_p
->ylen
* info_p
->costheta
)
1387 + (info_p
->xlen
* info_p
->sintheta
);
1390 mid2_p
->x
= info_p
->curvelist_p
->x
1391 + (2.0 * info_p
->xlen
* info_p
->costheta
)
1392 - (bulge_factor
* info_p
->ylen
* info_p
->sintheta
);
1393 mid2_p
->y
= info_p
->curvelist_p
->y
1394 + (bulge_factor
* info_p
->ylen
* info_p
->costheta
)
1395 + (2.0 * info_p
->xlen
* info_p
->sintheta
);
1398 if ((amount
= stick_out(info_p
)) <= 0.0) {
1399 /* This curve works. Go with it */
1404 /* Even max allowed bulge value was not enough. Returning the max bulge
1405 * allowed tells caller we failed, and adding on how much
1406 * "stick-out" gives an indication of how badly we failed.
1408 return(bulge_factor
+ amount
);
1412 /* adjust the endpoint of an inner note if the opposite end was adjusted,
1413 * and there is room to adjust this end. */
1416 inner_adj(gs_p
, note_p
, y_adj
, place
)
1418 struct GRPSYL
*gs_p
; /* not is in this group */
1419 struct NOTE
*note_p
; /* this is the note being tied to */
1420 double y_adj
; /* how much other end of tie was adjusted */
1421 int place
; /* PL_ABOVE or PL_BELOW */
1427 if (gs_p
->nnotes
<= 2) {
1428 /* can't possibly be an inner note, so no adjust */
1432 /* find index of note */
1433 for (i
= 0; i
< gs_p
->nnotes
; i
++) {
1434 if (note_p
== &(gs_p
->notelist
[i
])) {
1439 if (i
== gs_p
->nnotes
) {
1440 pfatal("couldn't find note in chord");
1443 if (i
== 0 || i
== gs_p
->nnotes
- 1) {
1444 /* not an inner note. no adjust */
1448 /* check if next note in chord is within STEPSIZE away. If not,
1449 * we can adjust this end */
1450 if (place
== PL_ABOVE
&& gs_p
->notelist
[i
-1].stepsup
1451 > gs_p
->notelist
[i
].stepsup
+ 1) {
1454 else if (place
== PL_BELOW
&& gs_p
->notelist
[i
+1].stepsup
1455 < gs_p
->notelist
[i
].stepsup
- 1) {
1456 /* y_adj will always come in as a positive number and will be
1457 * added on return, so return negative value for below curves */
1464 /* Returns the sum of the "stick out" of groups in the given curve.
1465 * If all groups are inside, this will be 0.0
1466 * Also counts number of "stickouts" that are near each end,
1467 * in case that might be useful in deciding which endpoint to move.
1468 * These counts are stored in the leftcount and rightcount fields of
1469 * the passed-in struct.
1475 struct TRYBULGE
*info_p
;
1478 struct GRPSYL
*gs_p
; /* to walk through list */
1479 struct GRPSYL
*begin_gs_p
, *end_gs_p
;
1480 double yleft
, yright
; /* y value of point on the line that is
1481 * at the x position of the left and right
1482 * sides of the current GRPSYL, */
1483 double yg
; /* y of group accounting for other phrases */
1484 struct MAINLL
*mll_p
; /* the curve's STUFF hangs off of here */
1485 int place
; /* PL_* */
1486 struct CRVLIST
*curvelist_p
; /* beginning of curve to check */
1487 struct CRVLIST
*endlist_p
; /* end of curve to check */
1490 double stickout
; /* return value */
1491 double len
; /* length that is deemed "near the end" of the
1492 * curve, for setting left/right counts */
1495 begin_gs_p
= info_p
->begin_gs_p
;
1496 end_gs_p
= info_p
->end_gs_p
;
1497 if (begin_gs_p
== 0 || end_gs_p
== 0) {
1498 pfatal("got null pointer when checking phrase marks");
1501 info_p
->leftcount
= 0;
1502 info_p
->rightcount
= 0;
1504 /* If starting phrase on last note of score or ending one on first
1505 * note of a score, begin and end will be the same. We know that
1506 * note has already been accounted for, so nothing to do. */
1507 if (begin_gs_p
== end_gs_p
) {
1511 staff
= begin_gs_p
->staffno
;
1512 voice
= begin_gs_p
->vno
;
1513 curvelist_p
= info_p
->curvelist_p
;
1514 endlist_p
= info_p
->endlist_p
;
1515 mll_p
= info_p
->mll_p
;
1516 place
= info_p
->place
;
1518 /* We will be counting up how many groups stick out near each end,
1519 * to potentially help decide which endpoint to move to avoid
1520 * collisions. For that purpose, we'll define "near the end"
1521 * as being within 1/4 of the total x distance from an endpoint.
1523 len
= (endlist_p
->x
- curvelist_p
->x
) / 4.0;
1525 /* Go through each group between the beginning and end. We've
1526 * already set the curve endings to clear the group boundaries */
1527 for (gs_p
= begin_gs_p
->next
; gs_p
!= end_gs_p
; gs_p
= gs_p
->next
) {
1529 /* If hit end of measure go to next measure */
1530 if (gs_p
== (struct GRPSYL
*) 0) {
1531 mll_p
= next_staff(staff
, mll_p
->next
);
1532 if (info_p
->mll_p
== (struct MAINLL
*) 0) {
1533 pfatal("fell off end of list while doing phrase marks");
1535 gs_p
= mll_p
->u
.staff_p
->groups_p
[voice
- 1];
1538 if (gs_p
== end_gs_p
) {
1542 /* Find out where the y of the curve is at this group.
1543 * We actually check two points, one each slightly
1544 * to the east and west of the group's x.
1545 * It would even more accurate to figure out the actual
1546 * width of whatever is at the end (a notehead, a stem,
1547 * a rest, stem with flag, etc) but just taking 1.5 Stepsizes
1548 * on either side generally gives adequate results and
1551 yleft
= curve_y_at_x(curvelist_p
, gs_p
->c
[AX
] - 1.5 * Stepsize
);
1552 yright
= curve_y_at_x(curvelist_p
, gs_p
->c
[AX
] + 1.5 * Stepsize
);
1554 /* See if this group is within the curve */
1555 if (info_p
->place
== PL_ABOVE
) {
1556 /* Consider the group (RN) plus any relevant
1557 * nested phrase marks (their space is stored in AN).
1558 * It is relevant unless it's for the begin group
1559 * and that group's east is not relevent, or it's the
1560 * end group and that group's west is not relevant */
1561 yg
= gs_p
->c
[RN
] + CLEARANCE
1562 + eff_tupext(gs_p
, mll_p
->u
.staff_p
, place
);
1563 if ( (gs_p
!= begin_gs_p
||
1564 ((gs_p
->phraseside
& EAST_SIDE
) == 0))
1565 && (gs_p
!= end_gs_p
||
1566 ((gs_p
->phraseside
& WEST_SIDE
) == 0)) ) {
1569 if (yleft
> yg
&& yright
> yg
) {
1570 /* Good. It's inside */
1574 /* Bad. It stuck over */
1575 stickout
+= yg
- MIN(yleft
, yright
);
1576 /* If near either end, make a note of that */
1577 if (gs_p
->c
[AX
] - curvelist_p
->x
< len
) {
1578 info_p
->leftcount
+= 1;
1580 else if (endlist_p
->x
- gs_p
->c
[AX
] < len
) {
1581 info_p
->rightcount
+=1;
1586 /* Do the same for curve going down */
1587 yg
= gs_p
->c
[RS
] - CLEARANCE
1588 + eff_tupext(gs_p
, mll_p
->u
.staff_p
, place
);
1589 if ( (gs_p
!= begin_gs_p
||
1590 ((gs_p
->phraseside
& EAST_SIDE
) == 0))
1591 && (gs_p
!= end_gs_p
||
1592 ((gs_p
->phraseside
& WEST_SIDE
) == 0)) ) {
1595 if (yleft
< yg
&& yright
< yg
) {
1599 stickout
+= MAX(yleft
, yright
) - yg
;
1600 if (gs_p
->c
[AX
] - curvelist_p
->x
< len
) {
1601 info_p
->leftcount
++;
1603 else if (endlist_p
->x
- gs_p
->c
[AX
] < len
) {
1604 info_p
->rightcount
++;
1613 /* find the x of the end of a tie/slur. Usually we could just used the west of
1614 * the group, but if there are lots of accidentals on notes that are far
1615 * away from the note in question, the end of the tie can come out rather
1616 * far away from its note. So try to see if we can move it closer, by
1617 * checking to see if there are any accidentals on notes nearby. This
1618 * function is not foolproof, sometimes leaving space when the tie/slur
1619 * could actually get threaded through a tiny opening, and sometimes
1620 * overwriting the edge of an accidental somewhat, but tries to do a better
1621 * job than the original single line of code for figuring this out had done. */
1624 tieslurx(gs_p
, note_p
, place
)
1626 struct GRPSYL
*gs_p
; /* check notes in this group */
1627 struct NOTE
*note_p
; /* check for accidentals near this note */
1628 int place
; /* PL_ABOVE or PL_BELOW to tell which side to look on */
1631 int n
; /* index through notelist */
1632 int acc
; /* accidental */
1635 /* if "wrong" side of a stem up group, better use group boundary */
1636 if (note_p
->c
[AX
] > gs_p
->c
[AX
] && gs_p
->stemdir
== UP
) {
1637 return(gs_p
->c
[AW
]);
1640 /* if there is another note nearby,
1641 * and that note has an accidental, better use
1642 * the west of the group to be safe, otherwise
1643 * use the west of the note. */
1644 for (n
= 0; n
< gs_p
->nnotes
; n
++) {
1646 acc
= gs_p
->notelist
[n
].accidental
;
1647 switch (gs_p
->notelist
[n
].stepsup
- note_p
->stepsup
) {
1650 /* close enough that sharp, flat, and dblflat may
1651 * interfere, if coming in from above */
1652 if (place
== PL_ABOVE
&& (acc
== '#' || acc
== '&'
1654 return(gs_p
->c
[AW
]);
1658 /* close enough that sharp may interfere, if coming
1660 if (place
== PL_ABOVE
&& acc
== '#') {
1661 return(gs_p
->c
[AW
]);
1665 /* the note itself */
1668 /* sharp, flat, and dblflat may interfere from
1669 * either direction */
1670 if (acc
== '#' || acc
== '&' || acc
== 'B') {
1671 return(gs_p
->c
[AW
]);
1678 /* close enough that things may interfere */
1679 if (place
== PL_BELOW
&& (acc
== '#' || acc
== '&'
1681 return(gs_p
->c
[AW
]);
1686 /* this note is too far away to matter */
1691 /* it seems there are no accidentals in the way, so use the note
1692 * boundary, rather than group boundary */
1693 return(gs_p
->c
[AX
] + notehorz(gs_p
, note_p
, AW
));
1697 /* given a main list struct, search forward from there for the STAFF matching
1698 * the given staff. If fall off end of main list, return NULL */
1700 static struct MAINLL
*
1701 next_staff(staff
, mll_p
)
1703 int staff
; /* find this staff number */
1704 struct MAINLL
*mll_p
; /* where to start */
1707 /* walk through main list looking for desired staff */
1708 for ( ; mll_p
!= (struct MAINLL
*) 0; mll_p
= mll_p
->next
) {
1709 if (mll_p
->str
== S_STAFF
) {
1710 if (mll_p
->u
.staff_p
->staffno
== staff
) {
1716 /* didn't find it */
1717 return( (struct MAINLL
*) 0);
1721 * Name: redo_steep()
1723 * Abstract: Redo curves that are very steep.
1727 * Description: If the curve is "too steep", it redoes it
1728 * so that it's horizontal at the outer end, rather than already
1729 * sloping in towards the inner end.
1730 * Caller needs to verify the redone curve doesn't collide
1731 * with any groups. Assumes the curve contains 3 points.
1735 redo_steep (first_p
, last_p
, place
)
1737 struct CRVLIST
*first_p
; /* left endpoint of curve */
1738 struct CRVLIST
*last_p
; /* right endpoint of curve */
1739 int place
; /* above or below */
1742 struct CRVLIST
*mid_p
; /* new midpoint of curve */
1743 float delx
; /* distance from the end to test */
1744 float a
, b
; /* some distances, see below */
1745 float midoff
; /* vert offset of midpoint */
1749 * We need to test whether either end of the curve is sloping in. So
1750 * we really should find the derivative at the endpoints. But we can
1751 * approximate it close enough by finding the y value at a point "near"
1752 * the end and comparing it to the end's y value. "delx" tells how
1753 * near. We'd like to set it to a millionth of an inch, but due to
1754 * apparent roundoff errors in curve_y_at_x(), we make it bigger than
1755 * that: 1/4 the curve length, but never more than 2 stepsizes.
1757 if (last_p
->x
- first_p
->x
> 8 * Stepsize
) {
1758 delx
= 2 * Stepsize
;
1760 delx
= (last_p
->x
- first_p
->x
) / 4.0;
1762 if (place
== PL_ABOVE
) {
1763 /* if both near points are higher than end points, return */
1764 if (curve_y_at_x(first_p
, first_p
->x
+ delx
) >= first_p
->y
&&
1765 curve_y_at_x(first_p
, last_p
->x
- delx
) >= last_p
->y
) {
1769 /* if both near points are lower than end points, return */
1770 if (curve_y_at_x(first_p
, first_p
->x
+ delx
) <= first_p
->y
&&
1771 curve_y_at_x(first_p
, last_p
->x
- delx
) <= last_p
->y
) {
1777 * The curve is steep. First, we choose a new point,
1778 * horizontally in the middle. We are
1779 * going to choose its vertical position so that the outer end of the
1780 * curve starts out horizontal.
1782 * Imagine the case of PL_BELOW where the left end is the outer (lower)
1783 * end. (The other 3 cases are symmetrical to this, and we can use the
1784 * analogous result.) Set the axes so that the left end is at the
1785 * origin, and the right end is at (2*a, b). The new point will be at
1786 * (a, y), and we have to find y. We know that y will be between 0 and
1787 * b/2. (Draw a picture.)
1789 * Draw segments from (0, 0) to (a, y), and (a, y) to (2*a, b). Then
1790 * draw a line through (a, y) such that it forms the same angle theta
1791 * with each of these segments. The way calccurve() works, it will
1792 * form two cubic arcs (in rotated coordinate systems) through the
1793 * three points, such that the slope of each arc at each point forms
1794 * the same angle theta with the segment next to it. The last line we
1795 * drew hits the X axis at a point which, with (0, 0) and (a, y) forms
1796 * an isoceles triangle, where the angles at (0, 0) and (a, y) are
1797 * both theta (because we're saying the arc at (0, 0) is horizontal).
1798 * So the other angle is 180 degrees minus 2*theta. That means the
1799 * other angle the line forms with the X axis is 2*theta. And that
1800 * means the angle between the horizontal line through (a, y) and the
1801 * second segment (a, y) to (2*a, b) is 3*theta.
1803 * Looking at triangle (0, 0) to (a, 0) to (a, y), we see that
1805 * Looking at triangle (a, y) to (2*a, y) to (2*a, b), we see that
1806 * tan(3*theta) = (b-y)/a
1807 * There is a trig identity
1808 * 3*tan(theta) - (tan(theta))^3
1809 * tan(3*theta) = ------------------------------
1810 * 1 - 3*(tan(theta))^2
1811 * Plug into this our values for tan(theta) and tan(3*theta), and you
1813 * 4 y^3 - 3 b y^2 - 4 a^2 y + a^2 b = 0
1814 * To solve this cubic, we could do a whole routine for solving cubics,
1815 * but it's easier to approximate as follows.
1818 * F(x) = 4 x^3 - 3 b x^2 - 4 a^2 x + a^2 b
1819 * a and b are positive. So at x = 0, F(x) > 0. At x=b/2, F(x) < 0.
1820 * Thus, as we expect, F(x) = 0 somewhere in between. For the
1821 * following algorithm to work, we need to know that F(x) is strictly
1822 * decreasing (the slope is always negative). The slope is
1823 * F'(x) = 12 x^2 - 6 b x - 4 a^2
1824 * (the derivative). It is a parabola opening upward and going through
1825 * (0, -4a^2) and (b/2, -4a^2). So it is always negative in this
1828 * The algorithm starts with lo = 0 and hi = b/2. It draws a straight
1829 * line between (lo, F(lo)) and (hi, F(hi)). The point where this
1830 * crosses the X axis we call "mid". Based on whether F(mid) is
1831 * positive or negative, we reset lo or hi to mid, and repeat the
1832 * process until F(mid) is within b/1000 of the axis. Then we will use
1833 * mid as our y value in the picture.
1835 a
= ABSDIFF(first_p
->x
, last_p
->x
) / 2.0;
1836 b
= ABSDIFF(first_p
->y
, last_p
->y
);
1838 midoff
= solvecubic(4.0, -3.0*b
, -4.0*a
*a
, a
*a
*b
, 0.0, b
/2.0, POINT
/2.0);
1840 mid_p
= first_p
->next
;
1841 mid_p
->x
= first_p
->x
+ a
; /* horizontally halfway between */
1843 /* handle the 4 cases, using the "mid" value for y in the diagram */
1844 if (place
== PL_ABOVE
) {
1845 if (first_p
->y
< last_p
->y
) {
1846 mid_p
->y
= last_p
->y
- midoff
;
1848 mid_p
->y
= first_p
->y
- midoff
;
1851 if (first_p
->y
< last_p
->y
) {
1852 mid_p
->y
= first_p
->y
+ midoff
;
1854 mid_p
->y
= last_p
->y
+ midoff
;
1860 /* do final refinements of curve.
1861 * Remove any really tiny line segments.
1862 * Then reset the group north or south boundaries to reflect
1863 * the inclusion of the phrase mark.
1867 final_touches(mll_p
, begin_gs_p
, end_gs_p
, curvelist_p
, place
)
1869 struct MAINLL
*mll_p
; /* points to first group in curve */
1870 struct GRPSYL
*begin_gs_p
; /* first group in curve */
1871 struct GRPSYL
*end_gs_p
; /* last group in curve */
1872 struct CRVLIST
*curvelist_p
; /* the curve */
1873 int place
; /* PL_ABOVE or PL_BELOW */
1878 int index
; /* in coord array: RN or RS */
1879 int adj_index
; /* in coord array: AN or AS. Used to store how much
1880 * to adjust for this phrase, in case there are
1881 * nested phrases. */
1882 float y_c
; /* y of curve */
1883 float x1
, y1
; /* lengths of segments in each dimension */
1884 float length
; /* of line segment */
1885 struct CRVLIST
*crvlist_p
;
1886 struct CRVLIST
*extra_p
; /* pointer to point to be freed */
1887 struct GRPSYL
*gs_p
; /* index through groups */
1890 if ( (mll_p
== (struct MAINLL
*) 0)
1891 || (begin_gs_p
== (struct GRPSYL
*) 0)
1892 || (end_gs_p
== (struct GRPSYL
*) 0)
1893 || (curvelist_p
== (struct CRVLIST
*) 0) ) {
1894 pfatal("null pointer in final_touches()");
1897 /* If there are really tiny line segments in a curve, the code for
1898 * tapering the curve has problems because if the width of the curve
1899 * is more than the length of the line and the angles work out just
1900 * wrong, various warts, sometimes huge ones, appear on the curves.
1901 * So go through the curve and if there are any really tiny lines,
1902 * throw away one of the points and make the remaining point the
1903 * average of what it was and what the discarded one was.
1904 * With the new way of calculating curves, this is probably now
1905 * unnecessary, but it seems safer to leave it in, just in case.
1907 for (crvlist_p
= curvelist_p
; crvlist_p
->next
!= (struct CRVLIST
*) 0;
1908 crvlist_p
= crvlist_p
->next
) {
1909 x1
= crvlist_p
->next
->x
- crvlist_p
->x
;
1910 y1
= crvlist_p
->next
->y
- crvlist_p
->y
;
1911 length
= sqrt(SQUARED(x1
) + SQUARED(y1
));
1912 if (length
< 0.01) {
1913 /* replace with average */
1914 crvlist_p
->x
= (crvlist_p
->x
+ crvlist_p
->next
->x
)
1916 crvlist_p
->y
= (crvlist_p
->y
+ crvlist_p
->next
->y
)
1918 /* take the extra out of the list */
1919 extra_p
= crvlist_p
->next
;
1920 if (crvlist_p
->next
->next
!= (struct CRVLIST
*) 0) {
1921 crvlist_p
->next
->next
->prev
= crvlist_p
;
1923 crvlist_p
->next
= crvlist_p
->next
->next
;
1924 if (crvlist_p
->next
== (struct CRVLIST
*) 0) {
1925 /* avoid trying to take ->next of null ptr */
1932 /* adjust north or south of each group within the curve to account for
1933 * the space needed for the curve */
1934 voice
= begin_gs_p
->vno
;
1935 staff
= begin_gs_p
->staffno
;
1936 if (place
== PL_ABOVE
) {
1945 for (gs_p
= begin_gs_p
; ; gs_p
= gs_p
->next
) {
1947 /* if hit end of measure go to next measure, skipping over
1948 * any empty measure (which could happen if vscheme changed
1949 * from 2 to 1 and back in the middle of the phrase) */
1950 while (gs_p
== (struct GRPSYL
*) 0) {
1951 mll_p
= next_staff(staff
, mll_p
->next
);
1952 if (mll_p
== (struct MAINLL
*) 0) {
1953 pfatal("fell off end of list while doing phrase marks");
1955 gs_p
= mll_p
->u
.staff_p
->groups_p
[voice
- 1];
1958 /* find where the curve y is at the x of the group, and
1959 * adjust the north or south of the group appropriately,
1960 * to be used later by any nesting phrase marks */
1961 y_c
= curve_y_at_x(curvelist_p
, gs_p
->c
[AX
]);
1963 /* check for an inner tie. They don't affect the boundary */
1964 if ( ((index
== RN
) && (y_c
< gs_p
->c
[index
])) ||
1965 ((index
== RS
) && (y_c
> gs_p
->c
[index
]))) {
1966 gs_p
->c
[adj_index
] = 0.0;
1969 if (place
== PL_ABOVE
) {
1970 gs_p
->c
[adj_index
] = (y_c
- gs_p
->c
[index
]
1974 gs_p
->c
[adj_index
] = - (gs_p
->c
[index
] - y_c
1979 if (gs_p
== end_gs_p
) {
1980 /* On the last group on the phrase, this phrase
1981 * only affects the west side--another phrase can
1982 * start on this same group with considering this one */
1983 gs_p
->phraseside
|= WEST_SIDE
;
1984 /* We are done with this curve */
1987 else if (gs_p
== begin_gs_p
){
1988 /* Only affects east side of first group */
1989 gs_p
->phraseside
|= EAST_SIDE
;
1992 /* not of the end, so both side are relevant */
1993 gs_p
->phraseside
|= (EAST_SIDE
| WEST_SIDE
);
1999 /* determine effective tuplet extension value. Normally, the tupext tells
2000 * us how much room to leave to allow for the tuplet bracket. However,
2001 * if the tuplet doesn't get a bracket, this can cause us to leave extra
2002 * space. Unfortunately, we do still need to leave room for the tuplet
2003 * number even if the bracket isn't there, and it's hard to know exactly
2004 * where the number is going to be. So we do the best we can: if the
2005 * group is the start or end of a tuplet and the tuplet does not get a
2006 * bracket, we ignore the tupext on that group. If it's in the middle
2007 * of a tuplet, we leave the tupext as is, because we can't tell for sure
2008 * whether we'll need it to get out of the way of the tuplet number or not.
2009 * But if this isn't a tuplet, or its bracket is on the opposite side
2010 * as where we're trying to put a curve, then it doesn't count as all.
2014 eff_tupext(gs_p
, staff_p
, side
)
2016 struct GRPSYL
*gs_p
;
2017 struct STAFF
*staff_p
;
2018 int side
; /* where the curve will be */
2021 /* if not a tuplet, return tupextend as is */
2022 if (gs_p
->tuploc
== NOITEM
) {
2023 return(gs_p
->tupextend
);
2026 /* if curve is on opposite side as tuplet bracket, ignore tupextend */
2027 if (side
!= tupdir(gs_p
, staff_p
)) {
2030 /* if group passed in is first group in a tuplet,
2031 * but the tuplet gets no bracket, ignore the tupextend */
2032 if (gs_p
->tuploc
== STARTITEM
) {
2033 if (tupgetsbrack(gs_p
) == NO
) {
2038 /* if group passed in is last group in a tuplet,
2039 * but the tuplet gets no bracket, ignore the tupextend */
2040 if (gs_p
->tuploc
== ENDITEM
) {
2041 /* first have to back up to find first group of tuplet,
2042 * because that's what tupgetsbrack() wants */
2045 if (gs_p
== (struct GRPSYL
*) 0) {
2046 pfatal("can't find tuplet start in eff_tupext");
2048 } while (gs_p
->tuploc
!= STARTITEM
);
2050 if (tupgetsbrack(gs_p
) == NO
) {
2055 /* if no special case applies, just return tupextend as is */
2056 return(gs_p
->tupextend
);
2060 /* determine correct bend direction for curve, return UP or DOWN */
2063 bulge_direction(mll_p
, gs1_p
, note_index
, curveno
)
2065 struct MAINLL
*mll_p
; /* main list struct pointing to gs1_p */
2066 struct GRPSYL
*gs1_p
; /* curve will be from note in gs1_p to note in gs2_p */
2067 int note_index
; /* which note in first group to tie */
2068 int curveno
; /* index into slurto, or -1 for a tie */
2071 struct GRPSYL
*gs_p
;
2072 RATIONAL vtime1
, vtime2
; /* beginning and ending time of group */
2073 int othervoice
; /* array index of other voice */
2076 /* If user explicitly set a bend direction, use that */
2077 if (curveno
== -1 && gs1_p
->notelist
[note_index
].tiedir
!= UNKNOWN
) {
2078 return(gs1_p
->notelist
[note_index
].tiedir
);
2080 else if (curveno
>= 0 && gs1_p
->notelist
[note_index
]
2081 .slurtolist
[curveno
].slurdir
!= UNKNOWN
) {
2082 return(gs1_p
->notelist
[note_index
].slurtolist
[curveno
].slurdir
);
2085 /* If there are 2 voices on the staff, bend is toward the stem */
2086 /* However, if the other voice is all spaces, pretend there is only
2088 if ( (mll_p
->u
.staff_p
->groups_p
[0] != (struct GRPSYL
*) 0)
2089 && (mll_p
->u
.staff_p
->groups_p
[1]
2090 != (struct GRPSYL
*) 0) ) {
2092 /* there are 2 voices */
2094 /* calculate begin and end time of tied group */
2096 for (gs_p
= mll_p
->u
.staff_p
->groups_p
[gs1_p
->vno
- 1];
2097 gs_p
!= gs1_p
; gs_p
= gs_p
->next
) {
2098 vtime1
= radd(vtime1
, gs_p
->fulltime
);
2101 /* ending time is vtime1 plus the length of group 1. If group
2102 * 1 is a grace note, use a very short time */
2103 if (EQ(gs1_p
->fulltime
, Zero
)) {
2107 tiny
.d
= 4 * MAXBASICTIME
;
2108 vtime2
= radd(vtime1
, tiny
);
2111 vtime2
= radd(vtime1
, gs1_p
->fulltime
);
2114 /* get array index of other voice to check it */
2115 othervoice
= (gs1_p
->vno
== 1 ?
1 : 0);
2117 if (hasspace(mll_p
->u
.staff_p
->groups_p
[othervoice
],
2118 vtime1
, vtime2
) == NO
) {
2119 /* there IS another voice, so stem goes opposite */
2120 return(gs1_p
->stemdir
);
2124 /* if only one voice (either because there is actually only one
2125 * or because there is effectively only one since the other is space)
2126 * and there is only one note in group, then bend is opposite stem */
2127 if (gs1_p
->nnotes
< 2) {
2128 /* quarter note grace groups are a special case, since they
2129 * don't have a stem (they are for showing prebends). So we
2130 * put the bend opposite the stem of the following group. */
2131 if (gs1_p
->grpvalue
== GV_ZERO
&& gs1_p
->basictime
== 4 &&
2132 gs1_p
->next
!= (struct GRPSYL
*) 0) {
2133 return(gs1_p
->next
->stemdir
== UP ? DOWN
: UP
);
2135 return(gs1_p
->stemdir
== UP ? DOWN
: UP
);
2138 /* if one voice on staff with more than one note in the group, all
2139 * bend opposite the stem except the top if the stem is up or the
2140 * bottom if the stem is down */
2141 if ( ((gs1_p
->stemdir
== DOWN
) && (note_index
== gs1_p
->nnotes
- 1))
2142 || ((gs1_p
->stemdir
== UP
) && (note_index
== 0)) ) {
2143 return(gs1_p
->stemdir
);
2146 return(gs1_p
->stemdir
== UP ? DOWN
: UP
);