| 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 | } |