chiark / gitweb /
Merge branch 'arkkra' into shiny
[mup] / mup / mup / phrase.c
CommitLineData
69695f33
MW
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 */
41struct 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
60static int nowhere_slide P((struct STUFF *stuff_p));
61static void do_nowhere P((struct STUFF *stuff_p, double x1, double y1,
62 double x2, double y2));
63static void curve_points P((struct MAINLL *mll_p, struct STUFF *stuff_p,
64 int is_phrase));
65static double inner_adj P((struct GRPSYL *gs_p, struct NOTE *note_p,
66 double y_adj, int place));
67static double stick_out P((struct TRYBULGE *info_p));
68static double try_bulge P((struct TRYBULGE *info_p));
69static double tieslurx P((struct GRPSYL *gs_p, struct NOTE *note_p, int place));
70static struct MAINLL *next_staff P((int staff, struct MAINLL *mll_p));
71static void redo_steep P((struct CRVLIST *first_p, struct CRVLIST *last_p,
72 int place));
73static 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));
75static double eff_tupext P((struct GRPSYL * gs_p, struct STAFF *staff_p, int side));
76static 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
84void
85phrase_points(mll_p, stuff_p)
86
87struct MAINLL *mll_p; /* MAINLL that stuff_p hangs off of */
88struct 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
97void
98tieslur_points(mll_p, stuff_p)
99
100struct MAINLL *mll_p; /* MAINLL that stuff_p hangs off of */
101struct 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
116void
117bend_points(mll_p, stuff_p)
118
119struct MAINLL *mll_p;
120struct 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
222void
223tabslur_points(mll_p, stuff_p)
224
225struct MAINLL *mll_p;
226struct 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
421static int
422nowhere_slide(stuff_p)
423
424struct 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
545static void
546do_nowhere(stuff_p, x1, y1, x2, y2)
547
548struct STUFF *stuff_p;
549double 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
574static void
575curve_points(mll_p, stuff_p, is_phrase)
576
577struct MAINLL *mll_p; /* MAINLL that stuff_p hangs off of */
578struct STUFF *stuff_p; /* info about the phrase mark or tie/slur */
579int 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
1354static double
1355try_bulge(info_p)
1356
1357struct 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
1415static double
1416inner_adj(gs_p, note_p, y_adj, place)
1417
1418struct GRPSYL *gs_p; /* not is in this group */
1419struct NOTE *note_p; /* this is the note being tied to */
1420double y_adj; /* how much other end of tie was adjusted */
1421int 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
1472static double
1473stick_out(info_p)
1474
1475struct 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
1623static double
1624tieslurx(gs_p, note_p, place)
1625
1626struct GRPSYL *gs_p; /* check notes in this group */
1627struct NOTE *note_p; /* check for accidentals near this note */
1628int 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
1700static struct MAINLL *
1701next_staff(staff, mll_p)
1702
1703int staff; /* find this staff number */
1704struct 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
1734static void
1735redo_steep (first_p, last_p, place)
1736
1737struct CRVLIST *first_p; /* left endpoint of curve */
1738struct CRVLIST *last_p; /* right endpoint of curve */
1739int 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
1866static void
1867final_touches(mll_p, begin_gs_p, end_gs_p, curvelist_p, place)
1868
1869struct MAINLL *mll_p; /* points to first group in curve */
1870struct GRPSYL *begin_gs_p; /* first group in curve */
1871struct GRPSYL *end_gs_p; /* last group in curve */
1872struct CRVLIST *curvelist_p; /* the curve */
1873int 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
2013static double
2014eff_tupext(gs_p, staff_p, side)
2015
2016struct GRPSYL *gs_p;
2017struct STAFF *staff_p;
2018int 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
2062static int
2063bulge_direction(mll_p, gs1_p, note_index, curveno)
2064
2065struct MAINLL *mll_p; /* main list struct pointing to gs1_p */
2066struct GRPSYL *gs1_p; /* curve will be from note in gs1_p to note in gs2_p */
2067int note_index; /* which note in first group to tie */
2068int 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}