chiark / gitweb /
Import upstream version 5.3.
[mup] / mup / mup / phrase.c
1
2 /* Copyright (c) 1995, 1996, 1997, 1998, 1999, 2001, 2002, 2005 by Arkkra Enterprises */
3 /* All rights reserved */
4
5 /* functions to determine the curves that make up phrase marks,
6  * ties and slurs. */
7
8 #include "defines.h"
9 #include "structs.h"
10 #include "globals.h"
11
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)
15
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)
25
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.
32  */
33 #define XOFFSET4CURVE   (0.75 * Stdpad)
34
35 /* Curves must be at least this far away from notes */
36 #define CLEARANCE       (3.0 * Stdpad)
37
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 */
41 struct TRYBULGE {
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 */
45         int place;                      /* PL_*  */
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 */
51         double costheta;
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 */
58 };
59
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,
64                 int is_phrase));
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,
72                 int place));
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));
78 \f
79
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. */
83
84 void
85 phrase_points(mll_p, stuff_p)
86
87 struct MAINLL *mll_p;           /* MAINLL that stuff_p hangs off of */
88 struct STUFF *stuff_p;          /* info about the phrase mark */
89
90 {
91         curve_points(mll_p, stuff_p, YES);
92 }
93 \f
94
95 /* figure out what points are needed for a tie or slur mark */
96
97 void
98 tieslur_points(mll_p, stuff_p)
99
100 struct MAINLL *mll_p;           /* MAINLL that stuff_p hangs off of */
101 struct STUFF *stuff_p;          /* info about the phrase mark */
102
103 {
104         /* if slide to/from nowhere in particular, do that */
105         if (nowhere_slide(stuff_p) == YES) {
106                 return;
107         }
108
109         curve_points(mll_p, stuff_p, NO);
110 }
111 \f
112
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 */
115
116 void
117 bend_points(mll_p, stuff_p)
118
119 struct MAINLL *mll_p;
120 struct STUFF *stuff_p;
121
122 {
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. */
134
135
136         /* first figure everything out as if it were a normal slur */
137         curve_points(mll_p, stuff_p, NO);
138
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.
146          */
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;
152                 FREE(one2discard_p);
153         }
154
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;
161
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;
165
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;
170         }
171         else if (xlen < 3.5 * V_HEIGHT) {
172                 v_height = 0.65 * V_HEIGHT;
173         }
174         else {
175                 v_height = V_HEIGHT;
176         }
177
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);
185                 return;
186         }
187
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);
191
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
200          *      slope = y / x
201          * Rearranging the first equation and substituing (slope * x) for y:
202          *      x^2 + (slope * x)^2 = v_height^2
203          * solve for x:
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.
207          *      y = x * slope
208          * Adjust for being relative to (midx, midy) and for bend direction
209          * and slope direction, and we are done.
210          */
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;
216 }
217 \f
218
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 */
221
222 void
223 tabslur_points(mll_p, stuff_p)
224
225 struct MAINLL *mll_p;
226 struct STUFF *stuff_p;
227
228 {
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,
236                                  * -2 to +2 */
237         int n, st;              /* index through notelist and slurtolist */
238
239
240         /* if slide to/from nowhere in particular, do that */
241         if (nowhere_slide(stuff_p) == YES) {
242                 return;
243         }
244
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);
252
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
256                  * one we find. */
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 */
265                                         break;
266                                 }
267                         }
268                         if (st < beggrp_p->notelist[n].nslurto) {
269                                 /* found it, so need to jump out */
270                                 break;
271                         }
272                 }
273                 if (n == beggrp_p->nnotes) {
274                         pfatal("can't find note being slid from");
275                 }
276                 begnote_p = &(beggrp_p->notelist[n]);
277         }
278         else {
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");
284                 }
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");
290
291                 if (endnote_p == (struct NOTE *) 0) {
292                         pfatal("failed to find endnote in tabslur_points");
293                 }
294         }
295
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) {
300                         slant = 1;
301                 }
302                 else {
303                         slant = -1;
304                 }
305         }
306         else {
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 */
309                 slant = 0;
310
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) {
316
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);
325
326                         /* error if the slide is between identical notes */
327                         if (acc1 == acc2) {
328                                 l_ufatal(endgrp_p->inputfile,
329                                                 endgrp_p->inputlineno,
330                                                 "can't slide to the same note");
331                         }
332                         else if (acc1 > acc2) {
333                                 slant = 1;
334                         }
335                         else {
336                                 slant = -1;
337                         }
338                 }
339
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) {
343 #ifdef __STDC__
344                         switch(notecomp( (const void *) begnote_p,
345                                                 (const void *) endnote_p)) {
346 #else
347                         switch(notecomp( (char *) begnote_p, (char *) endnote_p)) {
348 #endif
349                         case 1:
350                                 slant = 0.5;
351                                 break;
352                         case -1:
353                                 slant = -0.5;
354                                 break;
355                         default:
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);
360
361                                 /* error if the slide is
362                                  * between identical notes */
363                                 if (acc1 == acc2) {
364                                         l_ufatal(endgrp_p->inputfile,
365                                                 endgrp_p->inputlineno,
366                                                 "can't slide to the same note");
367                                 }
368                                 else if (acc1 > acc2) {
369                                         slant = 0.5;
370                                 }
371                                 else {
372                                         slant = -0.5;
373                                 }
374                                 break;
375                         }
376                 }
377         }
378
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)
386                         - 3.0 * Stepsize;
387                 curvelist_p->y = endnote_p->c[RY] + (slant * Stepsize);
388         }
389         else {
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);
393         }
394
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;
402         }
403         else  {
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;
407         }
408         curvelist_p->next->y = endnote_p->c[RY] - (slant * Stepsize);
409
410         /* attach to stuff */
411         stuff_p->crvlist_p = curvelist_p;
412
413         /* place doesn't really make sense, so set arbitrarily */
414         stuff_p->place = PL_ABOVE;
415 }
416 \f
417
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. */
420
421 static int
422 nowhere_slide(stuff_p)
423
424 struct STUFF *stuff_p;
425
426 {
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. */
432         struct GRPSYL *gs_p;
433         struct NOTE *note_p;
434         int n;
435         float slidexlen;        /* SLIDEXLEN * Staffscale */
436
437
438         if (stuff_p->curveno < 0) {
439                 return(NO);
440         }
441
442         if (stuff_p->begnote_p->nslurto == 0) {
443                 return(NO);
444         }
445
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) {
452                         break;
453                 }
454         }
455         if (n == gs_p->nnotes) {
456                 pfatal("couldn't find note in chord for slide");
457         }
458
459         slidexlen = SLIDEXLEN * Staffscale;
460
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) {
465
466         case IN_UPWARD:
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. */
479                 n++;
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]) {
483                         adjust = Stdpad;
484                 }
485                 do_nowhere(stuff_p,
486                         boundary, stuff_p->begnote_p->c[RY] - Stepsize + adjust,
487                         boundary + slidexlen, stuff_p->begnote_p->c[RY] + adjust);
488                 return(YES);
489
490         case IN_DOWNWARD:
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. */
495                 n--;
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]) {
499                         adjust = Stdpad;
500                 }
501                 do_nowhere(stuff_p,
502                         boundary, stuff_p->begnote_p->c[RY] + Stepsize - adjust,
503                         boundary + slidexlen, stuff_p->begnote_p->c[RY] - adjust);
504                 return(YES);
505
506         case OUT_UPWARD:
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,
510                  * dodge it */
511                 n--;
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]) {
515                         adjust = Stdpad;
516                 }
517                 do_nowhere(stuff_p,
518                         boundary - slidexlen, stuff_p->begnote_p->c[RY] - adjust,
519                         boundary, stuff_p->begnote_p->c[RY] + Stepsize - adjust);
520                 return(YES);
521
522         case OUT_DOWNWARD:
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 */
526                 n++;
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]) {
530                         adjust = Stdpad;
531                 }
532                 do_nowhere(stuff_p,
533                         boundary - slidexlen, stuff_p->begnote_p->c[RY] + adjust,
534                         boundary, stuff_p->begnote_p->c[RY] - Stepsize + adjust);
535                 return(YES);
536
537         default:
538                 return(NO);
539         }
540 }
541 \f
542
543 /* make a CRVLIST with the 2 given points and put it in the given stuff */
544
545 static void
546 do_nowhere(stuff_p, x1, y1, x2, y2)
547
548 struct STUFF *stuff_p;
549 double x1, y1, x2, y2;
550
551 {
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;
558
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;
562
563         /* place is not really relevant, but put something in it */
564         stuff_p->place = PL_ABOVE;
565 }
566 \f
567
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.
572  */
573
574 static void
575 curve_points(mll_p, stuff_p, is_phrase)
576
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 */
580
581 {
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
602                                  * rotation */
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 */
606
607
608         debug(32, "curve_points lineno %d", stuff_p->inputlineno );
609
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;
614         
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) {
618                 name = "phrase";
619                 if ( (begin_gs_p == (struct GRPSYL *) 0)
620                                 || (end_gs_p == (struct GRPSYL *) 0) ) {
621                         pfatal("no group associated with phrase");
622                 }
623         }
624         else {
625                 int indx;
626
627                 name = "tie/slur";
628                 if (begin_gs_p == (struct GRPSYL *) 0) {
629                         pfatal("no group associated with tie/slur");
630                 }
631                 /* figure out which direction to bend the tie/slur */
632                 if (stuff_p->carryin == YES) {
633                         struct MAINLL *m_p;
634                         struct GRPSYL *g_p;
635                         struct STUFF *st_p;
636
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.
643                          *
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.
650                          */
651
652                         /* First make sure we have the first group
653                          * in the measure. */
654                         for (g_p = begin_gs_p; g_p->prev != 0; g_p = g_p->prev) {
655                                 ;
656                         }
657
658                         /* Now find the MAINLL pointing to the prev meas */
659                         m_p = mll_p;
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");
663                         }
664
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;
670                                                         st_p = st_p->next) {
671                                 if (st_p == stuff_p->costuff_p) {
672                                         break;
673                                 }
674                         }
675                         if (st_p == 0) {
676                                 pfatal("failed to find costaff_p from mainll");
677                         }
678
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);
683                 }
684                 else {
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);
689                 }
690         }
691
692         place = stuff_p->place;
693
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) {
697                 side = RN;
698                 side_adj = AN;
699                 sign = 1.0;
700         }
701         else {
702                 side = RS;
703                 side_adj = AS;
704                 sign = -1.0;
705         }
706
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];
724                         }
725                 }
726                 else {
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));
730                 }
731         }
732
733         else { /* is tie or slur */
734
735                 curvelist_p->y = begnote_p->c[RY];
736                 y_adj = 0.0;
737
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]
750                                                         + (2.0 * Stdpad);
751                                 y_adj = (Stepsize * (begnote_p->notesize
752                                                 == GS_NORMAL ? 1.7 : 1.2));
753                                 curvelist_p->y -= y_adj;
754                         }
755                         else {
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;
760                         }
761                 }
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]
767                                         + (2.0 * Stdpad);
768                                 y_adj = (Stepsize * (begnote_p->notesize
769                                                 == GS_NORMAL ? 1.7 : 1.2));
770                                 curvelist_p->y += y_adj;
771                         }
772                         else {
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;
777                         }
778                 }
779
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;
795                         }
796                         else {
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;
801                         }
802                 }
803
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;
815                         }
816                         else {
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;
821                         }
822                 }
823                 else {
824                         curvelist_p->x = begin_gs_p->c[AX] +
825                                         notehorz(begin_gs_p, begnote_p, RE) +
826                                         Stdpad;
827                 }
828
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] &&
839                                 place == PL_ABOVE &&
840                                 stuff_p->carryin == NO) {
841                         curvelist_p->x += 1.5 * Stepsize;
842                 }
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] &&
850                                 place == PL_BELOW &&
851                                 stuff_p->carryin == NO) {
852                         curvelist_p->x += 1.5 * Stepsize;
853                 }
854                                 
855         }
856
857         /* if carried over from previous score, start a bit farther left */
858         if (stuff_p->carryin == YES) {
859
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 */
868                                         continue;
869                                 }
870                                 curvelist_p->x =
871                                         bar_mll_p->u.clefsig_p->bar_p->c[AE]
872                                         - (TIESLURPAD * Staffscale);
873
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.
881                                  */
882                                 if (begin_gs_p->c[AW] - curvelist_p->x > 5.0 * Stepsize) {
883                                         curvelist_p->x = begin_gs_p->c[AW]
884                                                         - 5.0 * Stepsize;
885                                 }
886                                 break;
887                         }
888                         else if (bar_mll_p->str == S_BAR) {
889                                 /* carryin to an ending */
890                                 curvelist_p->x = begin_gs_p->c[AW];
891                                 break;
892                         }
893                 }
894
895                 if (bar_mll_p == (struct MAINLL *) 0) {
896                         pfatal("missing CELFSIG when carrying over %s mark",
897                                                                 name);
898                 }
899         }
900
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];
916                         }
917                 }
918                 else {
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));
922                 }
923         }
924         else {
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];
930
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;
935                         }
936
937                         endlist_p->y = curvelist_p->y;
938                         end_gs_p = begin_gs_p;
939
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;
948                                 }
949                         }
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;
960                                 }
961                         }
962                 }
963                 else {
964                         /* not carryin */
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) {
968                                 /* this is a tie */
969                                 endnote_p = find_matching_note (end_gs_p,
970                                                 begnote_p->letter,
971                                                 begnote_p->octave, "tie");
972                         }
973                         else {
974                                 if (IS_NOWHERE(begnote_p->slurtolist
975                                                 [stuff_p->curveno].octave)) {
976                                         pfatal("curve_points called on slide to nowhere");
977                                 }
978
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,
984                                                 "slur/slide");
985                         }
986
987                         endlist_p->y = endnote_p->c[RY];
988
989                         y2_adj = 0.0;
990
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]
998                                                 - (2.0 * Stdpad);
999                                         y2_adj = (Stepsize *
1000                                                 (endnote_p->notesize
1001                                                 == GS_NORMAL ? 1.7 : 1.2));
1002                                         endlist_p->y -= y2_adj;
1003                                 }
1004                                 else {
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;
1010                                 }
1011                         }
1012
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]
1019                                                         - (2.0 * Stdpad);
1020                                         y2_adj = (Stepsize *
1021                                                 (endnote_p->notesize
1022                                                 == GS_NORMAL ? 1.7 : 1.2));
1023                                         endlist_p->y += y2_adj;
1024                                 }
1025                                 else {
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;
1031                                 }
1032                         }
1033
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]
1044                                                                 - Stdpad;
1045                                         y2_adj = (Stepsize *
1046                                                 (endnote_p->notesize
1047                                                 == GS_NORMAL ? 1.7 : 1.2));
1048                                         endlist_p->y -= y2_adj;
1049                                 }
1050                                 else {
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;
1056                                 }
1057                         }
1058
1059                         /* move if above and top note of stem up */
1060                         else if (end_gs_p->stemdir == UP && place == PL_ABOVE
1061                                         && endnote_p ==
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;
1067
1068                                 /* if tied from note is also the top of its
1069                                  * group, level the tie/slur */
1070                                 if (begin_gs_p->stemdir == UP &&
1071                                                 begnote_p ==
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));
1077                                 }
1078                         }
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);
1085                         }
1086                         else {
1087                                 endlist_p->x = tieslurx(end_gs_p, endnote_p,
1088                                         stuff_p->place) - (2.0 * Stdpad);
1089                         }
1090
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));
1103                         }
1104
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,
1111                                                         y_adj, place);
1112                         }
1113
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
1117                          * away. */
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);
1121                         }
1122                 }
1123         }
1124
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));
1141                 }
1142                 else if (place == PL_BELOW && begnote_p ==
1143                                 &(begin_gs_p->notelist[begin_gs_p->nnotes - 1])
1144                                 && endnote_p ==
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));
1149                 }
1150         }
1151
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 */
1155         
1156         /* if carrying over, extend x to margin */
1157         if (stuff_p->carryout) {
1158                 endlist_p->x = PGWIDTH - eff_rightmargin(mll_p);
1159         }
1160
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));
1164
1165         /* Find y length for creating bulge in the curve.
1166          * Make bigger bend if longer curve, but not too big or too small.
1167          */
1168         ylen = length / 16;
1169         if (ylen > 2.2 * Stepsize) {
1170                 ylen = 2.2 * Stepsize;
1171         }
1172         else if (ylen < (Stepsize * 0.75)) {
1173                 ylen = Stepsize * 0.75;
1174         }
1175         ylen = ylen * sign;
1176
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
1179          * belong */
1180         sintheta = (endlist_p->y - curvelist_p->y) / length;
1181         costheta = (endlist_p->x - curvelist_p->x) / length;
1182
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;
1189
1190         if (stuff_p->carryout == YES) {
1191                 if (is_phrase == YES) {
1192                         endlist_p->y += ylen / 2.0;
1193                 }
1194                 else {
1195                         end_gs_p = begin_gs_p;
1196                 }
1197         }
1198
1199         /* First try a single point in the middle. Try bigger bulge
1200          * value if some groups stick out, up to a maximum. */
1201         tb.mll_p = mll_p;
1202         tb.begin_gs_p = begin_gs_p;
1203         tb.end_gs_p = end_gs_p;
1204         tb.place = place;
1205         tb.curvelist_p = curvelist_p;
1206         tb.endlist_p = endlist_p;
1207         tb.xlen = length / 2.0;
1208         tb.ylen = ylen;
1209         tb.sintheta = sintheta;
1210         tb.costheta = costheta;
1211         tb.minbulge = MINBULGE;
1212         tb.maxbulge = MAXBULGE;
1213         try_p = &tb;
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.
1222                          */
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;
1230                         }
1231                 }
1232                 /* adjust group boundaries to include the curve */
1233                 final_touches(mll_p, begin_gs_p, end_gs_p, curvelist_p, place);
1234
1235                 /* attach the curve to the stuff */
1236                 stuff_p->crvlist_p = curvelist_p;
1237                 return;
1238         }
1239
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;
1247
1248         /* We now have three segments, each 1/3 of total length */
1249         tb.xlen = length / 3.0;
1250
1251         /* We're a little more desperate, so allow more bulge */
1252         tb.minbulge = MIN2BULGE;
1253         tb.maxbulge = MAX2BULGE;
1254
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);
1258
1259                 /* attach the curve to the stuff */
1260                 stuff_p->crvlist_p = curvelist_p;
1261                 return;
1262         }
1263
1264         /* Really getting desperate now, so allow even more bulge */
1265         tb.minbulge = MIN3BULGE;
1266         tb.maxbulge = MAX3BULGE;
1267
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.
1278          */
1279         found_good = NO;
1280         for (try = 0; try < 200; try++) {
1281                 double mvbegin, mvend, mvboth;
1282                 int leftcount, rightcount;
1283
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.
1287                  */
1288
1289                 /* try with just begin point moved */
1290                 curvelist_p->y += Stepsize * sign;
1291                 mvbegin = try_bulge(try_p);
1292
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;
1298
1299                 /* try with just end point moved */
1300                 curvelist_p->y -= Stepsize * sign;
1301                 mvend = try_bulge(try_p);
1302
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) {
1308                                 found_good = YES;
1309                                 break;
1310                         }
1311                 }
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) {
1318                                 found_good = YES;
1319                                 break;
1320                         }
1321                 }
1322                 else {
1323                         /* move both ends */
1324                         curvelist_p->y += Stepsize * sign;
1325                         if (mvboth < MAX3BULGE) {
1326                                 found_good = YES;
1327                                 break;
1328                         }
1329                 }
1330         }
1331
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);
1337
1338                 /* attach the curve to the stuff */
1339                 stuff_p->crvlist_p = curvelist_p;
1340                 return;
1341         }
1342
1343         pfatal("unable to find a usable curve");
1344 }
1345 \f
1346
1347 /* 
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
1351  * 3 or 4 points.
1352  */
1353
1354 static double
1355 try_bulge(info_p)
1356
1357 struct TRYBULGE *info_p;        /* points to all the info this func needs */
1358
1359 {
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 */
1364
1365
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;
1370         }
1371         else {
1372                 mid2_p = 0;
1373         }
1374
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) {
1379
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);
1388
1389                 if (mid2_p != 0) {
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);
1396                 }
1397
1398                 if ((amount = stick_out(info_p)) <= 0.0) {
1399                         /* This curve works. Go with it */
1400                         break;
1401                 }
1402         }
1403
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.
1407          */
1408         return(bulge_factor + amount);
1409 }
1410 \f
1411
1412 /* adjust the endpoint of an inner note if the opposite end was adjusted,
1413  * and there is room to adjust this end. */
1414
1415 static double
1416 inner_adj(gs_p, note_p, y_adj, place)
1417
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 */
1422
1423 {
1424         int i;
1425
1426
1427         if (gs_p->nnotes <= 2) {
1428                 /* can't possibly be an inner note, so no adjust */
1429                 return(0.0);
1430         }
1431
1432         /* find index of note */
1433         for (i = 0; i < gs_p->nnotes; i++) {
1434                 if (note_p == &(gs_p->notelist[i])) {
1435                         break;
1436                 }
1437         }
1438
1439         if (i == gs_p->nnotes) {
1440                 pfatal("couldn't find note in chord");
1441         }
1442
1443         if (i == 0 || i == gs_p->nnotes - 1) {
1444                 /* not an inner note. no adjust */
1445                 return(0.0);
1446         }
1447
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) {
1452                 return(y_adj);
1453         }
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 */
1458                 return(-y_adj);
1459         }
1460         return(0.0);
1461 }
1462 \f
1463
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.
1470  */
1471
1472 static double
1473 stick_out(info_p)
1474
1475 struct TRYBULGE *info_p;
1476
1477 {
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 */
1488         int staff;
1489         int voice;
1490         double stickout;        /* return value */
1491         double len;             /* length that is deemed "near the end" of the
1492                                  * curve, for setting left/right counts */
1493
1494
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");
1499         }
1500
1501         info_p->leftcount = 0;
1502         info_p->rightcount = 0;
1503
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) {
1508                 return(0.0);
1509         }
1510
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;
1517         stickout = 0.0;
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.
1522          */
1523         len = (endlist_p->x - curvelist_p->x) / 4.0;
1524
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) {
1528
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");
1534                         }
1535                         gs_p = mll_p->u.staff_p->groups_p[voice - 1];
1536                 }
1537
1538                 if (gs_p == end_gs_p) {
1539                         break;
1540                 }
1541
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
1549                  * is a lot simpler.
1550                  */
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);
1553
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)) ) {
1567                                 yg += gs_p->c[AN];
1568                         }
1569                         if (yleft > yg && yright > yg) {
1570                                 /* Good. It's inside */
1571                                 continue;
1572                         }
1573                         else {
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;
1579                                 }
1580                                 else if (endlist_p->x - gs_p->c[AX] < len) {
1581                                         info_p->rightcount +=1;
1582                                 }
1583                         }
1584                 }
1585                 else {
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)) ) {
1593                                 yg += gs_p->c[AS];
1594                         }
1595                         if (yleft < yg && yright < yg) {
1596                                 continue;
1597                         }
1598                         else {
1599                                 stickout += MAX(yleft, yright) - yg;
1600                                 if (gs_p->c[AX] - curvelist_p->x < len) {
1601                                         info_p->leftcount++;
1602                                 }
1603                                 else if (endlist_p->x - gs_p->c[AX] < len) {
1604                                         info_p->rightcount++;
1605                                 }
1606                         }
1607                 }
1608         }
1609         return(stickout);
1610 }
1611 \f
1612
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. */
1622
1623 static double
1624 tieslurx(gs_p, note_p, place)
1625
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 */
1629
1630 {
1631         int n;          /* index through notelist */
1632         int acc;        /* accidental */
1633
1634
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]);
1638         }
1639
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++) {
1645
1646                 acc = gs_p->notelist[n].accidental;
1647                 switch (gs_p->notelist[n].stepsup - note_p->stepsup) {
1648                 case 1:
1649                 case 2:
1650                         /* close enough that sharp, flat, and dblflat may
1651                          * interfere, if coming in from above */
1652                         if (place == PL_ABOVE && (acc == '#' || acc == '&'
1653                                                         || acc == 'B')) {
1654                                 return(gs_p->c[AW]);
1655                         }
1656                         break;
1657                 case 3:
1658                         /* close enough that sharp may interfere, if coming
1659                          * in from above */
1660                         if (place == PL_ABOVE && acc == '#') {
1661                                 return(gs_p->c[AW]);
1662                         }
1663                         break;
1664                 case 0:
1665                         /* the note itself */
1666                         break;
1667                 case -1:
1668                         /* sharp, flat, and dblflat may interfere from
1669                          * either direction */
1670                         if (acc == '#' || acc == '&' || acc == 'B') {
1671                                 return(gs_p->c[AW]);
1672                         }
1673                         break;
1674
1675                 case -2:
1676                 case -3:
1677                 case -4:
1678                         /* close enough that things may interfere */
1679                         if (place == PL_BELOW && (acc == '#' || acc == '&'
1680                                                         || acc == 'B')) {
1681                                 return(gs_p->c[AW]);
1682                         }
1683                         break;
1684
1685                 default:
1686                         /* this note is too far away to matter */
1687                         break;
1688                 }
1689         }
1690
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));
1694 }
1695 \f
1696
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 */
1699
1700 static struct MAINLL *
1701 next_staff(staff, mll_p)
1702
1703 int staff;              /* find this staff number */
1704 struct MAINLL *mll_p;   /* where to start */
1705
1706 {
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) {
1711                                 return(mll_p);
1712                         }
1713                 }
1714         }
1715
1716         /* didn't find it */
1717         return( (struct MAINLL *) 0);
1718 }
1719 \f
1720 /*
1721  * Name:        redo_steep()
1722  *
1723  * Abstract:    Redo curves that are very steep.
1724  *
1725  * Returns:     void
1726  *
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.
1732  */
1733
1734 static void
1735 redo_steep (first_p, last_p, place)
1736
1737 struct CRVLIST *first_p;        /* left endpoint of curve */
1738 struct CRVLIST *last_p;         /* right endpoint of curve */
1739 int place;                      /* above or below */
1740
1741 {
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 */
1746
1747
1748         /*
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.
1756          */
1757         if (last_p->x - first_p->x > 8 * Stepsize) {
1758                 delx = 2 * Stepsize;
1759         } else {
1760                 delx = (last_p->x - first_p->x) / 4.0;
1761         }
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) {
1766                         return;
1767                 }
1768         } else {
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) {
1772                         return;
1773                 }
1774         }
1775
1776         /*
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.
1781          *
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.)
1788          *
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.
1802          *
1803          * Looking at triangle (0, 0) to (a, 0) to (a, y), we see that
1804          *      tan(theta) = y/a
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
1812          * end up with
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.
1816          *
1817          # Define
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
1826          * interval.
1827          *
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.
1834          */
1835         a = ABSDIFF(first_p->x, last_p->x) / 2.0;
1836         b = ABSDIFF(first_p->y, last_p->y);
1837
1838         midoff= solvecubic(4.0, -3.0*b, -4.0*a*a, a*a*b, 0.0, b/2.0, POINT/2.0);
1839
1840         mid_p = first_p->next;
1841         mid_p->x = first_p->x + a;      /* horizontally halfway between */
1842
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;
1847                 } else {
1848                         mid_p->y = first_p->y - midoff;
1849                 }
1850         } else {
1851                 if (first_p->y < last_p->y) {
1852                         mid_p->y = first_p->y + midoff;
1853                 } else {
1854                         mid_p->y = last_p->y + midoff;
1855                 }
1856         }
1857 }
1858 \f
1859
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.
1864  */
1865
1866 static void
1867 final_touches(mll_p, begin_gs_p, end_gs_p, curvelist_p, place)
1868
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 */
1874
1875 {
1876         int voice;      
1877         int staff;
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 */
1888
1889
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()");
1895         }
1896
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.
1906          */
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)
1915                                                                 / 2.0;
1916                         crvlist_p->y = (crvlist_p->y + crvlist_p->next->y)
1917                                                                 / 2.0;
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;
1922                         }
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 */
1926                                 break;
1927                         }
1928                         FREE(extra_p);
1929                 }
1930         }
1931
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) {
1937                 index = RN;
1938                 adj_index = AN;
1939         }
1940         else {
1941                 index = RS;
1942                 adj_index = AS;
1943         }
1944
1945         for (gs_p = begin_gs_p;     ; gs_p = gs_p->next) {
1946
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");
1954                         }
1955                         gs_p = mll_p->u.staff_p->groups_p[voice - 1];
1956                 }
1957
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]);
1962
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;
1967                 }
1968                 else {
1969                         if (place == PL_ABOVE) {
1970                                 gs_p->c[adj_index] = (y_c - gs_p->c[index]
1971                                                                 + Stepsize);
1972                         }
1973                         else {
1974                                 gs_p->c[adj_index] =  - (gs_p->c[index] - y_c
1975                                                                 + Stepsize);
1976                         }
1977                 }
1978
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 */
1985                         break;
1986                 }
1987                 else if (gs_p == begin_gs_p){
1988                         /* Only affects east side of first group */
1989                         gs_p->phraseside |= EAST_SIDE;
1990                 }
1991                 else {
1992                         /* not of the end, so both side are relevant */
1993                         gs_p->phraseside |= (EAST_SIDE | WEST_SIDE);
1994                 }
1995         }
1996 }
1997 \f
1998
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.
2011  */
2012
2013 static double
2014 eff_tupext(gs_p, staff_p, side)
2015
2016 struct GRPSYL *gs_p;
2017 struct STAFF *staff_p;
2018 int side;               /* where the curve will be */
2019
2020 {
2021         /* if not a tuplet, return tupextend as is */
2022         if (gs_p->tuploc == NOITEM) {
2023                 return(gs_p->tupextend);
2024         }
2025
2026         /* if curve is on opposite side as tuplet bracket, ignore tupextend */
2027         if (side != tupdir(gs_p, staff_p)) {
2028                 return(0.0);
2029         }
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) {
2034                         return(0.0);
2035                 }
2036         }
2037
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 */
2043                 do {
2044                         gs_p = gs_p->prev;
2045                         if (gs_p == (struct GRPSYL *) 0) {
2046                                 pfatal("can't find tuplet start in eff_tupext");
2047                         }
2048                 } while (gs_p->tuploc != STARTITEM);
2049
2050                 if (tupgetsbrack(gs_p) == NO) {
2051                         return(0.0);
2052                 }
2053         }
2054
2055         /* if no special case applies, just return tupextend as is */
2056         return(gs_p->tupextend);
2057 }
2058 \f
2059
2060 /* determine correct bend direction for curve, return UP or DOWN */
2061
2062 static int
2063 bulge_direction(mll_p, gs1_p, note_index, curveno)
2064
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 */
2069
2070 {
2071         struct GRPSYL *gs_p;
2072         RATIONAL vtime1, vtime2;        /* beginning and ending time of group */
2073         int othervoice;                 /* array index of other voice */
2074
2075
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);
2079         }
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);
2083         }
2084
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
2087          * one voice */
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) ) {
2091
2092                 /* there are 2 voices */
2093
2094                 /* calculate begin and end time of tied group */
2095                 vtime1 = Zero;
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);
2099                 }
2100
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)) {
2104                         RATIONAL tiny;
2105
2106                         tiny.n = 1;
2107                         tiny.d = 4 * MAXBASICTIME;
2108                         vtime2 = radd(vtime1, tiny);
2109                 }
2110                 else {
2111                         vtime2 = radd(vtime1, gs1_p->fulltime);
2112                 }
2113
2114                 /* get array index of other voice to check it */
2115                 othervoice = (gs1_p->vno == 1 ? 1 : 0);
2116
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);
2121                 }
2122         }
2123
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);
2134                 }
2135                 return(gs1_p->stemdir == UP ? DOWN : UP);
2136         }
2137         
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);
2144         }
2145         else {
2146                 return(gs1_p->stemdir == UP ? DOWN : UP);
2147         }
2148 }