| 1 | /* Copyright (c) 1995, 1996, 1997, 1999, 2000, 2001, 2002, 2003 by Arkkra Enterprises */ |
| 2 | /* All rights reserved */ |
| 3 | |
| 4 | /* This file contains functions that deal with |
| 5 | * extending underscores and dashes on lyric syllables. |
| 6 | */ |
| 7 | |
| 8 | #include "defines.h" |
| 9 | #include "structs.h" |
| 10 | #include "globals.h" |
| 11 | |
| 12 | static double end_dashes P((struct MAINLL *mll_p, struct GRPSYL *syl_p, |
| 13 | int verse, int place, int *carryover_p)); |
| 14 | static double end_underscore P((struct MAINLL *mll_p, struct GRPSYL *syl_p, |
| 15 | int verse, int place, int *carryover_p)); |
| 16 | static double endx P((struct GRPSYL *last_grp_p, double end)); |
| 17 | static int has_above_lyr P((struct MAINLL *mll_p, RATIONAL begin_time, |
| 18 | struct GRPSYL *group_p, int verse)); |
| 19 | static int voice_is_above P((int v1, int v2)); |
| 20 | static struct GRPSYL *find_verse_place P((struct STAFF *staff_p, |
| 21 | int verse, int place)); |
| 22 | static RATIONAL default_end P((struct MAINLL *mll_p, struct GRPSYL *syl_p, |
| 23 | RATIONAL start_time, double *end_p)); |
| 24 | static int bar_ends_extender P((struct BAR *bar_p, struct MAINLL *mll_p, |
| 25 | int staffno, int verse, int place, |
| 26 | struct GRPSYL **nextsyl_p_p)); |
| 27 | static void pr_extender P((int ch, double start, double end, double y, |
| 28 | int font, int size)); |
| 29 | static void insert_carryover_syllable P((struct MAINLL *mll_p, int staffno, |
| 30 | int sylplace, int verseno, char *dash_or_underscore, |
| 31 | int font, int size)); |
| 32 | static void add_syllable P((struct STAFF *staff_p, int sylplace, int verseno, |
| 33 | char *dash_or_underscore, int font, int size, |
| 34 | double begin_x, struct CHORD *chord_p)); |
| 35 | static void stitch_syl_into_chord P((struct CHORD *chord_p, |
| 36 | struct GRPSYL *syl_gs_p)); |
| 37 | \f |
| 38 | |
| 39 | /* This function is called on lyric syllables in two cases: |
| 40 | * 1) During placement phase to determine if an extender needs to |
| 41 | * be carried over to a following staff. In this case, really_print |
| 42 | * will be NO. (The easiest way to see if an extender needs to carry |
| 43 | * over is to pretend to print an extender). The return value will |
| 44 | * be YES if there should be a carryover. |
| 45 | * 2) When printing the syllable, to draw an extender after it, |
| 46 | * if appropriate. In this case, really_print will be YES, |
| 47 | * and the return value is meaningless. |
| 48 | * |
| 49 | * If a syllable ends with a dash, the dash should be placed halfway between |
| 50 | * where this syllable ends and the next begins. Or if there is a big space, |
| 51 | * multiple dashes should be spread out in that space. If it ends with an |
| 52 | * underscore, then an underline should be drawn from the end of this |
| 53 | * syllable to the east edge of the notes in the last chord before |
| 54 | * the next syllable for the same staff/verse/place. |
| 55 | * But if there is a carryover, this just does the extender up to the |
| 56 | * end of the current score; it will get called again on the next score |
| 57 | * to continue the extender. |
| 58 | * If an underscore is used on a single chord, rather than a mellisma |
| 59 | * (which might technically be considered an "incorrect" usage of underscore), |
| 60 | * we figure the underscore should be drawn to just before the next syllable, |
| 61 | * unless there is a rest earlier. Or if the next syllable begins a measure, |
| 62 | * the underscore ends before the bar line, to look better. |
| 63 | * If really printing, the dash or underscore is removed |
| 64 | * from the end of the string so it won't get printed |
| 65 | * with the syllable. |
| 66 | */ |
| 67 | |
| 68 | int |
| 69 | spread_extender(syl_p, mll_p, verse, sylplace, really_print) |
| 70 | |
| 71 | struct GRPSYL *syl_p; /* current syllable */ |
| 72 | struct MAINLL *mll_p; /* which MAINLL struct it's hanging off of */ |
| 73 | int verse; /* verse number */ |
| 74 | int sylplace; /* PL_ABOVE, etc */ |
| 75 | int really_print; /* if YES, actually print, otherwise just return |
| 76 | * whether needs to be carried over to next score */ |
| 77 | |
| 78 | { |
| 79 | char *syl; /* to walk through characters of the syllable */ |
| 80 | int font; |
| 81 | int size; |
| 82 | double start; /* dash area or underscore starts here */ |
| 83 | double end; /* dash area or underscore ends here */ |
| 84 | int ch; /* current character in syllable */ |
| 85 | int last_ch = '\0'; /* final character in syllable */ |
| 86 | int extndr_font; /* in case user changes font/size after |
| 87 | * extender, keep track of what font/size the |
| 88 | * extender was */ |
| 89 | int extndr_size = -1; |
| 90 | char *ch_p; /* pointer to where - or _ is in string */ |
| 91 | int carryover; /* YES if will carry over to next staff */ |
| 92 | |
| 93 | |
| 94 | |
| 95 | /* See if there is a dash or underscore at the end of the syllable. |
| 96 | * If so, save pointer to it. Note that this may not be the last |
| 97 | * byte in the string, because there could be font/size changes |
| 98 | * after it. */ |
| 99 | font = syl_p->syl[0]; |
| 100 | size = syl_p->syl[1]; |
| 101 | syl = syl_p->syl + 2; |
| 102 | |
| 103 | /* These two assignments avoid "used without being set" warnings */ |
| 104 | extndr_font = font; |
| 105 | ch_p = syl; |
| 106 | |
| 107 | /* Find last character of syllable */ |
| 108 | while ( (ch = next_str_char( &syl, &font, &size)) != '\0') { |
| 109 | #ifdef EXTCHAR |
| 110 | if ( ( ch == '-' || ch == '_') && ! IS_MUSIC_FONT(font) |
| 111 | && (font < FONT_XTR) ) { |
| 112 | #else |
| 113 | if ( ( ch == '-' || ch == '_') && ! IS_MUSIC_FONT(font) ) { |
| 114 | #endif |
| 115 | ch_p = syl - 1; |
| 116 | extndr_font = font; |
| 117 | extndr_size = size; |
| 118 | last_ch = ch; |
| 119 | } |
| 120 | else { |
| 121 | last_ch = '\0'; |
| 122 | } |
| 123 | } |
| 124 | |
| 125 | /* If there is an extender, handle it */ |
| 126 | if (last_ch != '\0') { |
| 127 | if ( last_ch == '-') { |
| 128 | end = end_dashes(mll_p, syl_p, verse, sylplace, |
| 129 | &carryover); |
| 130 | } |
| 131 | else { |
| 132 | end = end_underscore(mll_p, syl_p, verse, sylplace, |
| 133 | &carryover); |
| 134 | } |
| 135 | |
| 136 | if (really_print == NO) { |
| 137 | return(carryover); |
| 138 | } |
| 139 | |
| 140 | /* Move the rest of the string |
| 141 | * over the dash or underscore, |
| 142 | * so it won't get printed with the syllable */ |
| 143 | do { |
| 144 | *ch_p = *(ch_p + 1); |
| 145 | } while ( *++ch_p != '\0'); |
| 146 | start = syl_p->c[AE]; |
| 147 | |
| 148 | /* procsyls() adjusted the east in certain cases for |
| 149 | * placement purposes. For printing we need to cancel out |
| 150 | * those adjustments. */ |
| 151 | if (syl_p->next != 0 && last_ch != '-') { |
| 152 | start -= width(extndr_font, extndr_size, ' '); |
| 153 | } |
| 154 | if (syl_p->next == 0 && last_ch == '-') { |
| 155 | start += width(extndr_font, extndr_size, ' '); |
| 156 | } |
| 157 | |
| 158 | /* actually print the extender */ |
| 159 | pr_extender(last_ch, start, end, syl_p->c[AY], |
| 160 | extndr_font, extndr_size); |
| 161 | } |
| 162 | return(NO); |
| 163 | } |
| 164 | \f |
| 165 | |
| 166 | /* Given a syllable ending with a dash, and some other info, |
| 167 | * return where to end the dash(es). If the dashes carry over |
| 168 | * to the following score, this will return a point near the east end of |
| 169 | * the current score, after setting *carryover_p to YES. |
| 170 | */ |
| 171 | |
| 172 | static double |
| 173 | end_dashes(mll_p, syl_p, verse, place, carryover_p) |
| 174 | |
| 175 | struct MAINLL *mll_p; /* points to STAFF containing the syl with dash */ |
| 176 | struct GRPSYL *syl_p; /* this is the syllable with dash */ |
| 177 | int verse; /* which verse the syl_p is for */ |
| 178 | int place; /* a PL_* value for where the lyric is */ |
| 179 | int *carryover_p; /* return value, set to YES if there was a carryover */ |
| 180 | |
| 181 | { |
| 182 | int staffno; |
| 183 | struct BAR *lastbar_p; |
| 184 | |
| 185 | staffno = syl_p->staffno; |
| 186 | *carryover_p = NO; |
| 187 | lastbar_p = 0; /* will get set to something better before being used */ |
| 188 | syl_p = syl_p->next; |
| 189 | |
| 190 | do { |
| 191 | /* Go forward looking for another non-space syllable */ |
| 192 | if (syl_p != 0) { |
| 193 | for ( ; syl_p != 0; syl_p = syl_p->next) { |
| 194 | if (syl_p->grpcont != GC_SPACE) { |
| 195 | /* found it! */ |
| 196 | return(syl_p->c[AW] - Stepsize); |
| 197 | } |
| 198 | } |
| 199 | } |
| 200 | |
| 201 | /* No ending syl in current measure. Try the next. */ |
| 202 | for (mll_p = mll_p->next; mll_p != 0; mll_p = mll_p->next) { |
| 203 | if (mll_p->str == S_BAR) { |
| 204 | if (bar_ends_extender(mll_p->u.bar_p, |
| 205 | mll_p, staffno, verse, |
| 206 | place, 0) == YES) { |
| 207 | return(mll_p->u.bar_p->c[AW] - Stepsize); |
| 208 | } |
| 209 | lastbar_p = mll_p->u.bar_p; |
| 210 | } |
| 211 | |
| 212 | else if (mll_p->str == S_FEED) { |
| 213 | /* If this is a feed at the very end of the |
| 214 | * main list, or one or more blocks follow it, |
| 215 | * this is not the kind of feed |
| 216 | * we're looking for. */ |
| 217 | if (mll_p->next == 0 || |
| 218 | mll_p->next->str == S_BLOCKHEAD) { |
| 219 | continue; |
| 220 | } |
| 221 | /* There is a carryover unless the |
| 222 | * pseudo-bar is something that would end |
| 223 | * the extender. */ |
| 224 | mll_p = mll_p->next; |
| 225 | if (mll_p->str != S_CLEFSIG |
| 226 | || mll_p->u.clefsig_p->bar_p |
| 227 | == 0) { |
| 228 | if (mll_p->str == S_FEED) { |
| 229 | /* Being here means there is |
| 230 | * a bug somewhere else, |
| 231 | * because the main list rules |
| 232 | * are violated. But we can |
| 233 | * render such a bug harmless |
| 234 | * by continuing here. |
| 235 | */ |
| 236 | continue; |
| 237 | } |
| 238 | pfatal("end_dashes found unexpected main list contents after feed"); |
| 239 | } |
| 240 | if (bar_ends_extender(mll_p->u.clefsig_p->bar_p, |
| 241 | mll_p, staffno, verse, place, 0) |
| 242 | == NO) { |
| 243 | *carryover_p = YES; |
| 244 | } |
| 245 | return(lastbar_p->c[AW] - Stepsize); |
| 246 | } |
| 247 | |
| 248 | else if (mll_p->str == S_STAFF |
| 249 | && mll_p->u.staff_p->staffno |
| 250 | == staffno) { |
| 251 | syl_p = find_verse_place(mll_p->u.staff_p, |
| 252 | verse, place); |
| 253 | break; |
| 254 | } |
| 255 | } |
| 256 | } while (mll_p != 0); |
| 257 | |
| 258 | /* Fell off end of song. Use final bar */ |
| 259 | return(lastbar_p->c[AW] - Stepsize); |
| 260 | } |
| 261 | \f |
| 262 | |
| 263 | /* Given a syllable ending with an underscore, and some other info, |
| 264 | * return where to end the underscore. If the underscore carries over |
| 265 | * to the following score, this will return a point near the east end of |
| 266 | * the current score, after setting *carryover_p to YES. |
| 267 | */ |
| 268 | |
| 269 | static double |
| 270 | end_underscore(mll_p, syl_p, verse, place, carryover_p) |
| 271 | |
| 272 | struct MAINLL *mll_p; /* points to STAFF containing the syl with underscore */ |
| 273 | struct GRPSYL *syl_p; /* this is the syllable with underscore */ |
| 274 | int verse; /* which verse the syl_p is for */ |
| 275 | int place; /* a PL_* value for where the lyric is */ |
| 276 | int *carryover_p; /* return value, set to YES if there was a carryover */ |
| 277 | |
| 278 | { |
| 279 | struct GRPSYL *current_grp_p[MAXVOICES];/* which group we are |
| 280 | * currently dealing with on |
| 281 | * each voice */ |
| 282 | RATIONAL group_time[MAXVOICES]; /* accumulated time value of |
| 283 | * groups up to the one we |
| 284 | * are currently dealing with */ |
| 285 | short had_rest[MAXVOICES]; /* YES or NO */ |
| 286 | RATIONAL current_time; /* how far we are in meas */ |
| 287 | RATIONAL end_time; /* where next non-space |
| 288 | * syllable is for this |
| 289 | * staff/place/verse, if |
| 290 | * there is one |
| 291 | * in the current measure, |
| 292 | * otherwise the end of the |
| 293 | * current measure. */ |
| 294 | struct GRPSYL *last_grp_p; /* if non-zero, this is the |
| 295 | * current candidate group |
| 296 | * with which we could |
| 297 | * potentially align the |
| 298 | * end of the underscore. */ |
| 299 | double end; /* this is how far we will |
| 300 | * draw the underscore if we |
| 301 | * don't find any reason to |
| 302 | * stop it sooner. */ |
| 303 | struct GRPSYL *grp_p; /* walk through GRPSYLs */ |
| 304 | struct STAFF *staff_p; /* next measure's STAFF */ |
| 305 | struct GRPSYL *nextsyl_p; /* syl list for same verse/place |
| 306 | * in the next measure */ |
| 307 | RATIONAL grp_end_time; /* where a current group ends */ |
| 308 | |
| 309 | int vindex; /* voice index */ |
| 310 | int v; /* voice index */ |
| 311 | short found_feed; /* YES or NO */ |
| 312 | int staffno; |
| 313 | |
| 314 | |
| 315 | *carryover_p = NO; /* assume no carryover for now */ |
| 316 | staffno = mll_p->u.staff_p->staffno; |
| 317 | |
| 318 | /* Back up from the syllable with underscore to count up time-wise how |
| 319 | * far into the measure it is */ |
| 320 | current_time = Zero; |
| 321 | for (grp_p = syl_p->prev; grp_p != 0; grp_p = grp_p->prev) { |
| 322 | current_time = radd(current_time, grp_p->fulltime); |
| 323 | } |
| 324 | |
| 325 | /* Set a default end time and place. |
| 326 | * Most likely, we will discover later we need to stop the underscore |
| 327 | * earlier than this, but if the user is using underscore in a strange |
| 328 | * way, like on a single long note rather than a melissma, |
| 329 | * we'll use this as the default place to end the underscore. */ |
| 330 | end_time = default_end(mll_p, syl_p, current_time, &end); |
| 331 | |
| 332 | /* We don't yet have any candidate group with which to align |
| 333 | * the ending of the underscore. */ |
| 334 | last_grp_p = 0; |
| 335 | |
| 336 | /* For each voice, if it exists, find the group that contains |
| 337 | * the time of the syllable with the underscore, and make that |
| 338 | * the "current group" for that voice. If the voice doesn't exist, |
| 339 | * set the current group pointer to zero. */ |
| 340 | staff_p = mll_p->u.staff_p; |
| 341 | for (vindex = 0; vindex < MAXVOICES; vindex++) { |
| 342 | group_time[vindex] = Zero; |
| 343 | had_rest[vindex] = NO; |
| 344 | if (staff_p->groups_p[vindex] != 0) { |
| 345 | for (current_grp_p[vindex] = staff_p->groups_p[vindex]; |
| 346 | current_grp_p[vindex] != 0; |
| 347 | current_grp_p[vindex] |
| 348 | = current_grp_p[vindex]->next) { |
| 349 | if (GE(current_time, group_time[vindex]) && |
| 350 | LT(current_time, |
| 351 | radd(group_time[vindex], |
| 352 | current_grp_p[vindex]->fulltime))) { |
| 353 | /* This group contains the syl's time */ |
| 354 | |
| 355 | if (current_grp_p[vindex]->grpcont == GC_REST) { |
| 356 | had_rest[vindex] = YES; |
| 357 | } |
| 358 | break; |
| 359 | } |
| 360 | group_time[vindex] = radd(group_time[vindex], |
| 361 | current_grp_p[vindex]->fulltime); |
| 362 | } |
| 363 | if (current_grp_p[vindex] == 0) { |
| 364 | pfatal("unable to find group containing syl's time"); |
| 365 | } |
| 366 | } |
| 367 | else { |
| 368 | /* voice doesn't exist in this measure */ |
| 369 | current_grp_p[vindex] = 0; |
| 370 | } |
| 371 | } |
| 372 | |
| 373 | for ( ; ; ) { |
| 374 | /* Most of the time, we use voice 1 to determine where to |
| 375 | * end the underscore. However, if voice 1 has spaces, |
| 376 | * we'll use voice 3 (the "middle" voice), and |
| 377 | * if that is non-existent or space, we use voice 2. |
| 378 | * If everything is space, we keep going and hope for the |
| 379 | * best. If all else fails, we would end up using the "end" |
| 380 | * value as the default. |
| 381 | * |
| 382 | * However, if this is a below or between lyric, |
| 383 | * and there exists an above lyric |
| 384 | * during the time we are dealing with, |
| 385 | * we assume voice 1 goes with the above lyric, and the |
| 386 | * below lyric probably goes with voice 2, or possibly voice 3. |
| 387 | * If both those voices exist, it's probably not possible |
| 388 | * to divine which the user wants the lyric associated with |
| 389 | * without reading their mind. But 3 voices on a vocal staff |
| 390 | * is quite unusual, especially with rests in different places, |
| 391 | * so we use voice 2 if it exists and is non-space. |
| 392 | * If that fails, we try 3, then 1, then punt. |
| 393 | * If it is a between lyric, there is a slight chance the user |
| 394 | * really wanted us to use the staff below, but we always |
| 395 | * associate "between" things with the staff above. |
| 396 | * They should use "above" on the next staff instead. |
| 397 | */ |
| 398 | vindex = 0; /* use voice 1 as default */ |
| 399 | if (place != PL_ABOVE) { |
| 400 | /* The lyric is below or between. |
| 401 | * Test voices 2, 3, and 1 (indexes 1, 2, 0) |
| 402 | * in that order till we find one that isn't a space, |
| 403 | * and see if there is an above lyric |
| 404 | * during its time. If so, that is the voice to use |
| 405 | * during this time to figure out |
| 406 | * where to end underscore. */ |
| 407 | if (current_grp_p[1] != 0 && |
| 408 | current_grp_p[1]->grpcont != GC_SPACE && |
| 409 | has_above_lyr(mll_p, current_time, |
| 410 | current_grp_p[1], verse) == YES) { |
| 411 | vindex = 1; |
| 412 | } |
| 413 | else if (current_grp_p[2] != 0 && |
| 414 | current_grp_p[2]->grpcont != GC_SPACE && |
| 415 | has_above_lyr(mll_p, current_time, |
| 416 | current_grp_p[2], verse) == YES) { |
| 417 | vindex = 2; |
| 418 | } |
| 419 | /* Otherwise we go with the default, voice 1. |
| 420 | * We know voice 1 will always exist. */ |
| 421 | } |
| 422 | |
| 423 | else { /* place is above */ |
| 424 | /* Note that voice 1 always exists, so |
| 425 | * so we don't need to check for null first |
| 426 | * on that voice. */ |
| 427 | if (current_grp_p[0]->grpcont != GC_SPACE) { |
| 428 | vindex = 0; |
| 429 | } |
| 430 | else if (current_grp_p[2] != 0 && |
| 431 | current_grp_p[2]->grpcont != GC_SPACE) { |
| 432 | vindex = 2; |
| 433 | } |
| 434 | else if (current_grp_p[1] != 0 && |
| 435 | current_grp_p[1]->grpcont != GC_SPACE) { |
| 436 | vindex = 1; |
| 437 | } |
| 438 | } |
| 439 | |
| 440 | /* At this point, we know which voice is most relevant for |
| 441 | * checking if it is time to end the underscore. |
| 442 | * See if the current group in that voice contains the |
| 443 | * time value of the ending syllable. */ |
| 444 | if ( GE(end_time, group_time[vindex]) && LT(end_time, |
| 445 | radd(group_time[vindex], |
| 446 | current_grp_p[vindex]->fulltime)) ) { |
| 447 | /* We need to end the underscore now. */ |
| 448 | return(endx(last_grp_p, end)); |
| 449 | } |
| 450 | |
| 451 | /* If the relevant group is a rest, need to stop here */ |
| 452 | if (current_grp_p[vindex]->grpcont == GC_REST) { |
| 453 | return(endx(last_grp_p, current_grp_p[vindex]->c[AW])); |
| 454 | } |
| 455 | else if (current_grp_p[vindex]->grpcont == GC_NOTES) { |
| 456 | /* Save as last known group so far at which we |
| 457 | * could potentially end the underscore. */ |
| 458 | last_grp_p = current_grp_p[vindex]; |
| 459 | } |
| 460 | |
| 461 | /* We're done with this group; move to next */ |
| 462 | current_time = radd(current_time, |
| 463 | current_grp_p[vindex]->fulltime); |
| 464 | |
| 465 | /* Catch up all the voices to the current time */ |
| 466 | for (v = 0; v < MAXVOICES; v++) { |
| 467 | if (current_grp_p[v] != 0) { |
| 468 | grp_end_time = radd(group_time[v], |
| 469 | current_grp_p[v]->fulltime); |
| 470 | |
| 471 | while ( LE(grp_end_time, current_time) ){ |
| 472 | /* Special case. Suppose, |
| 473 | * as an example, soprano and |
| 474 | * alto share a staff and the |
| 475 | * soprano has a long note |
| 476 | * while the alto has a |
| 477 | * melissma. The underscore |
| 478 | * should then go to the |
| 479 | * last note of the melissma, |
| 480 | * even though soprano is |
| 481 | * the reference voice. |
| 482 | * However, if the alto line |
| 483 | * had had rests, it's likely |
| 484 | * it's just accompaniment, |
| 485 | * not a vocal line, or at |
| 486 | * least they should have |
| 487 | * used separate above/below |
| 488 | * lyrics. |
| 489 | * So if this group is below |
| 490 | * the reference group and |
| 491 | * hasn't had any rests and |
| 492 | * is east of our candidate |
| 493 | * last group, make it the |
| 494 | * new candidate last group. */ |
| 495 | if (voice_is_above(vindex, v) |
| 496 | && place != PL_ABOVE |
| 497 | && had_rest[v] == NO |
| 498 | && last_grp_p != 0 |
| 499 | && current_grp_p[v]->grpcont |
| 500 | == GC_NOTES |
| 501 | && current_grp_p[v]->c[AX] |
| 502 | > last_grp_p->c[AX]) { |
| 503 | last_grp_p = current_grp_p[v]; |
| 504 | } |
| 505 | |
| 506 | /* move on to next group */ |
| 507 | current_grp_p[v] = |
| 508 | current_grp_p[v]->next; |
| 509 | if (current_grp_p[v] == 0) { |
| 510 | break; |
| 511 | } |
| 512 | |
| 513 | group_time[v] = grp_end_time; |
| 514 | grp_end_time = radd( |
| 515 | group_time[v], |
| 516 | current_grp_p[v]->fulltime); |
| 517 | if (current_grp_p[v]->grpcont |
| 518 | == GC_REST) { |
| 519 | had_rest[v] = YES; |
| 520 | } |
| 521 | } |
| 522 | } |
| 523 | } |
| 524 | |
| 525 | /* Are we now at the end of the current measure? */ |
| 526 | if (current_grp_p[vindex] == 0) { |
| 527 | /* If there is a feed after this bar, |
| 528 | * we need to see if a carryover is needed. |
| 529 | * If so, we will end this underscore just before |
| 530 | * the bar, and carry it over to the next score. |
| 531 | */ |
| 532 | found_feed = NO; |
| 533 | for (mll_p = mll_p->next; mll_p != 0; mll_p = mll_p->next) { |
| 534 | if (mll_p->str == S_BAR) { |
| 535 | if (bar_ends_extender(mll_p->u.bar_p, mll_p, |
| 536 | syl_p->staffno, verse, |
| 537 | place, &nextsyl_p) |
| 538 | == YES) { |
| 539 | /* It's not clear |
| 540 | * where we should stop if |
| 541 | * we can't deduce a following |
| 542 | * syllable. However, |
| 543 | * if we go to the bar line, |
| 544 | * the user can always use |
| 545 | * a <> syllable to force |
| 546 | * an earlier ending if needed, |
| 547 | * whereas if we go |
| 548 | * with the last group, |
| 549 | * there's probably no |
| 550 | * reasonable workaround |
| 551 | * if that's not what they want, |
| 552 | * so use the bar line. */ |
| 553 | if (nextsyl_p == 0) { |
| 554 | return(end); |
| 555 | } |
| 556 | else if (nextsyl_p->grpcont |
| 557 | == GC_SPACE) { |
| 558 | /* "carries over" */ |
| 559 | return(end); |
| 560 | } |
| 561 | else { |
| 562 | return(endx(last_grp_p, end)); |
| 563 | } |
| 564 | } |
| 565 | } |
| 566 | else if (mll_p->str == S_FEED) { |
| 567 | found_feed = YES; |
| 568 | } |
| 569 | else if (mll_p->str == S_STAFF && |
| 570 | mll_p->u.staff_p->staffno == |
| 571 | staffno) { |
| 572 | break; |
| 573 | } |
| 574 | else if (mll_p->str == S_SSV) { |
| 575 | /* if this staff becomes invisible, |
| 576 | * end the underscore at the last |
| 577 | * group before that. */ |
| 578 | struct SSV *ssv_p; |
| 579 | ssv_p = mll_p->u.ssv_p; |
| 580 | if (ssv_p->context == C_STAFF |
| 581 | && ssv_p->staffno == staffno |
| 582 | && ssv_p->used[VISIBLE] == YES |
| 583 | && ssv_p->visible == NO) { |
| 584 | return(endx(last_grp_p, end)); |
| 585 | } |
| 586 | } |
| 587 | } |
| 588 | if (mll_p == 0) { |
| 589 | /* fell off end of song */ |
| 590 | return(endx(last_grp_p, end)); |
| 591 | } |
| 592 | staff_p = mll_p->u.staff_p; |
| 593 | |
| 594 | /* See if there is a syllable at the same verse/place */ |
| 595 | if ((nextsyl_p = find_verse_place(staff_p, |
| 596 | verse, place)) != 0 && |
| 597 | nextsyl_p->grpcont != GC_SPACE) { |
| 598 | /* There is a syllable at the |
| 599 | * beginning of the next meas, |
| 600 | * so we end the underscore, |
| 601 | * unless it was just a carryover syllable |
| 602 | * that we added earlier. */ |
| 603 | if (nextsyl_p->syl[2] != '_' |
| 604 | || nextsyl_p->syl[3] != '\0') { |
| 605 | return(endx(last_grp_p, end)); |
| 606 | } |
| 607 | } |
| 608 | if (found_feed == YES) { |
| 609 | if (staff_p->groups_p[vindex] != 0 && |
| 610 | staff_p->groups_p[vindex]->grpcont == GC_REST) { |
| 611 | /* next meas begins with a rest, |
| 612 | * so no need to carry over */ |
| 613 | return(endx(last_grp_p, end)); |
| 614 | } |
| 615 | /* We need to end the underscore on the |
| 616 | * current score, and arrange to carry it |
| 617 | * over on the next score. */ |
| 618 | *carryover_p = YES; |
| 619 | return(end); |
| 620 | } |
| 621 | |
| 622 | |
| 623 | /* Move to next measure by initing each |
| 624 | * current_grp_p[vindex] to the first group |
| 625 | * in the next measure. */ |
| 626 | for (vindex = 0; vindex < MAXVOICES; vindex++) { |
| 627 | current_grp_p[vindex] = staff_p->groups_p[vindex]; |
| 628 | group_time[vindex] = Zero; |
| 629 | if (current_grp_p[vindex] != 0 && |
| 630 | current_grp_p[vindex]->grpcont |
| 631 | == GC_REST) { |
| 632 | had_rest[vindex] = YES; |
| 633 | } |
| 634 | } |
| 635 | end_time = default_end(mll_p, |
| 636 | find_verse_place(staff_p, verse, place), |
| 637 | Zero, &end); |
| 638 | current_time = Zero; |
| 639 | } |
| 640 | } |
| 641 | } |
| 642 | \f |
| 643 | |
| 644 | /* If we found a last group where we could end a underscore, |
| 645 | * return where the east edge of its notes are, |
| 646 | * otherwise return the "end" value as the default. |
| 647 | */ |
| 648 | |
| 649 | static double |
| 650 | endx(last_grp_p, end) |
| 651 | |
| 652 | struct GRPSYL *last_grp_p; /* if != 0, use east edge of notes of this */ |
| 653 | double end; /* if all else fails, use this */ |
| 654 | |
| 655 | { |
| 656 | int n; /* note index */ |
| 657 | double edge; /* return value */ |
| 658 | |
| 659 | |
| 660 | if (last_grp_p == 0) { |
| 661 | return(end); |
| 662 | } |
| 663 | |
| 664 | if (last_grp_p->grpcont != GC_NOTES) { |
| 665 | /* This should actually never happen with the current code, |
| 666 | * but just in case, we use the east of the group */ |
| 667 | return(last_grp_p->c[AE]); |
| 668 | } |
| 669 | |
| 670 | /* find east edge of notes, not counting any dots or flags */ |
| 671 | edge = -1000000.0; /* init to impossible value */ |
| 672 | for (n = 0; n < last_grp_p->nnotes; n++) { |
| 673 | if (last_grp_p->notelist[n].c[AE] > edge) { |
| 674 | edge = last_grp_p->notelist[n].c[AE]; |
| 675 | } |
| 676 | } |
| 677 | /* If the edge we calculated is east of the default end, use |
| 678 | * the default end, because that is suppose to be the farthest |
| 679 | * possible east we can be. This could happen if the user used |
| 680 | * <^....> on a lyric to force part of the lyric to encroach |
| 681 | * into the previous groups' space. In that case we need to end |
| 682 | * the underscore where the encroaching lyric begins, not where |
| 683 | * the last note group ends. |
| 684 | */ |
| 685 | if (edge > end) { |
| 686 | return(end); |
| 687 | } |
| 688 | return(edge); |
| 689 | } |
| 690 | \f |
| 691 | |
| 692 | /* |
| 693 | * Return YES if there is an above lyrics during the specified time. |
| 694 | * We have to use some heuristics. |
| 695 | * |
| 696 | * If there is any non-space above lyric for the given verse |
| 697 | * at any point between the begin time |
| 698 | * and the begin time plus the fulltime of the group_p, |
| 699 | * then there is an above lyric. |
| 700 | * |
| 701 | * If there is a rest on voice 1, that implies a rest in an above lyric |
| 702 | * line. |
| 703 | * |
| 704 | * If there is lyric space for the duration in question, either |
| 705 | * explicit space, or just no above lyrics at all for the given verse |
| 706 | * in this measure, then we don't know for sure where there are no |
| 707 | * above lyrics, or there is an earlier above lyric for this verse |
| 708 | * that extends into the duration. |
| 709 | * If we find some earlier non-space above lyric |
| 710 | * and it ends with an extender (dash or underscore), |
| 711 | * we say there is an above lyric. |
| 712 | * If there is no such lyric, or the first non-space above lyric |
| 713 | * lyric we come to in backing up does not end with an extender, |
| 714 | * we say there isn't an above lyric. |
| 715 | */ |
| 716 | |
| 717 | static int |
| 718 | has_above_lyr(mll_p, begin_time, group_p, verse) |
| 719 | |
| 720 | struct MAINLL *mll_p; /* points to syl's STAFF */ |
| 721 | RATIONAL begin_time; |
| 722 | struct GRPSYL *group_p; /* see if there a lyric above this group */ |
| 723 | int verse; |
| 724 | |
| 725 | { |
| 726 | struct STAFF *staff_p; |
| 727 | struct GRPSYL *grp_p; |
| 728 | RATIONAL cumm_time; /* current cummulative time */ |
| 729 | RATIONAL new_cumm_time; /* cumm_time + group's fulltime */ |
| 730 | RATIONAL end_time; /* begin_time + syl's fulltime */ |
| 731 | int n; /* syllist index */ |
| 732 | int prev_extends; /* YES/NO if prev syl has extender */ |
| 733 | |
| 734 | |
| 735 | if (mll_p->str != S_STAFF) { |
| 736 | pfatal("has_above_lyr passed wrong type of struct"); |
| 737 | } |
| 738 | |
| 739 | staff_p = mll_p->u.staff_p; |
| 740 | end_time = radd(begin_time, group_p->fulltime); |
| 741 | |
| 742 | /* Go through syllists for the staff */ |
| 743 | prev_extends = NO; |
| 744 | for (n = 0; n < staff_p->nsyllists; n++) { |
| 745 | if (staff_p->sylplace[n] == PL_ABOVE && |
| 746 | staff_p->syls_p[n]->vno == verse) { |
| 747 | cumm_time = Zero; |
| 748 | for (grp_p = staff_p->syls_p[n]; grp_p != 0; grp_p = grp_p->next) { |
| 749 | new_cumm_time = radd(cumm_time, grp_p->fulltime); |
| 750 | |
| 751 | if ( LT(new_cumm_time, begin_time) && |
| 752 | grp_p->grpcont != GC_SPACE) { |
| 753 | prev_extends = has_extender(grp_p->syl); |
| 754 | } |
| 755 | |
| 756 | /* See if this syllable overlaps the time |
| 757 | * of the group we are checking against. */ |
| 758 | else if ( (GE(begin_time, cumm_time) && |
| 759 | LT(begin_time, new_cumm_time)) || |
| 760 | (GE(end_time, cumm_time) && |
| 761 | LT(end_time, new_cumm_time)) ) { |
| 762 | |
| 763 | /* This is a relevant group. If it isn't |
| 764 | * a space, then we know there is |
| 765 | * indeed an above lyric. */ |
| 766 | if (grp_p->grpcont != GC_SPACE) { |
| 767 | return(YES); |
| 768 | } |
| 769 | if (prev_extends == YES) { |
| 770 | /* A syllable |
| 771 | * earlier in the measure |
| 772 | * is extending into the |
| 773 | * duration, so that counts. |
| 774 | */ |
| 775 | return(YES); |
| 776 | } |
| 777 | } |
| 778 | else if (GT(new_cumm_time, end_time)) { |
| 779 | /* we're past the relevant syl(s) */ |
| 780 | break; |
| 781 | } |
| 782 | cumm_time = new_cumm_time; |
| 783 | } |
| 784 | /* We've dealt with the only relevant syl list |
| 785 | * in this measure. */ |
| 786 | break; |
| 787 | } |
| 788 | } |
| 789 | |
| 790 | /* If there is a rest on voice 1, there is an implicit above |
| 791 | * lyric (albeit a pause in the above lyrics). Or at least it hardly |
| 792 | * makes sense to use voice 1 for below/between lyrics if voice 1 |
| 793 | * is a rest but there is another voice below it that isn't. |
| 794 | */ |
| 795 | cumm_time = Zero; |
| 796 | for (grp_p = mll_p->u.staff_p->groups_p[0]; grp_p != 0; grp_p = grp_p->next) { |
| 797 | new_cumm_time = radd(cumm_time, grp_p->fulltime); |
| 798 | if ( (GE(begin_time, cumm_time) && |
| 799 | LT(begin_time, new_cumm_time)) || |
| 800 | (GE(end_time, cumm_time) && |
| 801 | LT(end_time, new_cumm_time)) ) { |
| 802 | if (grp_p->grpcont == GC_REST) { |
| 803 | return(YES); |
| 804 | } |
| 805 | } |
| 806 | cumm_time = new_cumm_time; |
| 807 | if (GT(cumm_time, end_time)) { |
| 808 | /* past the relevant groups */ |
| 809 | break; |
| 810 | } |
| 811 | } |
| 812 | |
| 813 | /* If we got here, we weren't able to tell for |
| 814 | * sure if there is an above lyric, because there |
| 815 | * was either implicit or explicit space. |
| 816 | * Most likely there is no above lyric, |
| 817 | * but there is a slight possibility there is |
| 818 | * a lyric holding over into this time period |
| 819 | * via a melisma or tied notes from a previous measure. |
| 820 | * So we back up looking for such a lyric. If we find an above lyric |
| 821 | * that ends with an extender (underscore or dash), |
| 822 | * we declare that there is an above lyric. |
| 823 | * If we find one without an extender or back up |
| 824 | * all the way to the beginning of the song without |
| 825 | * finding any above lyric, there is no above lyric here. |
| 826 | * But we give up after 20 measures, figuring it's |
| 827 | * really unlikely for any melisma or tie to last |
| 828 | * that long, especially since any scorefeeds |
| 829 | * would cause a syllable to get added. The exact |
| 830 | * value of 20 is arbitrary; it just seems like plenty. |
| 831 | * |
| 832 | * prevgrpsyl doesn't work on syls, just groups, |
| 833 | * but by giving it staff_p->groups_p[0] (we |
| 834 | * know voice 1 will always exist), it will give |
| 835 | * us the mll_p for the staff we need. |
| 836 | */ |
| 837 | for (n = 0; n < 20; n++) { |
| 838 | struct GRPSYL *last_non_space_p; |
| 839 | |
| 840 | if (prevgrpsyl(mll_p->u.staff_p->groups_p[0], |
| 841 | &mll_p) == 0) { |
| 842 | /* Got to beginning of song */ |
| 843 | return(NO); |
| 844 | } |
| 845 | |
| 846 | grp_p = find_verse_place(mll_p->u.staff_p, verse, PL_ABOVE); |
| 847 | |
| 848 | if (grp_p == 0) { |
| 849 | /* No relevant lyrics in this meas */ |
| 850 | continue; |
| 851 | } |
| 852 | |
| 853 | last_non_space_p = 0; |
| 854 | for ( ; grp_p != 0; grp_p = grp_p->next) { |
| 855 | if (grp_p->grpcont != GC_SPACE) { |
| 856 | last_non_space_p = grp_p; |
| 857 | } |
| 858 | } |
| 859 | if (last_non_space_p != 0) { |
| 860 | /* Found a preceeding syllable */ |
| 861 | return(has_extender(last_non_space_p->syl)); |
| 862 | } |
| 863 | } |
| 864 | /* We've backed up far enough that the chances of there actually being |
| 865 | * an above lyrics are very, very slim. */ |
| 866 | return(NO); |
| 867 | } |
| 868 | \f |
| 869 | |
| 870 | /* Returns YES if voice with index v1 is "above" voice v2; else NO */ |
| 871 | |
| 872 | static int |
| 873 | voice_is_above(v1, v2) |
| 874 | |
| 875 | int v1; |
| 876 | int v2; |
| 877 | |
| 878 | { |
| 879 | /* Voice number is one more than its index, so convert index to |
| 880 | * number so it's easier to think about */ |
| 881 | v1++; |
| 882 | v2++; |
| 883 | |
| 884 | /* Voice 1 is above voice 2 and 3 */ |
| 885 | if (v1 == 1) { |
| 886 | return(YES); |
| 887 | } |
| 888 | |
| 889 | /* Voice 3 is the "middle" voice and thus "above" voice 2 */ |
| 890 | if (v1 == 3 && v2 == 2) { |
| 891 | return(YES); |
| 892 | } |
| 893 | |
| 894 | return(NO); |
| 895 | } |
| 896 | \f |
| 897 | |
| 898 | /* Given a STAFF, return the first GRPSYL in the syllable list for the given |
| 899 | * verse and place, if one exists. Otherwise return 0. |
| 900 | */ |
| 901 | |
| 902 | static struct GRPSYL * |
| 903 | find_verse_place(staff_p, verse, place) |
| 904 | |
| 905 | struct STAFF *staff_p; |
| 906 | int verse; |
| 907 | int place; |
| 908 | |
| 909 | { |
| 910 | int n; |
| 911 | |
| 912 | for (n = 0; n < staff_p->nsyllists; n++) { |
| 913 | if (staff_p->sylplace[n] == place && |
| 914 | staff_p->syls_p[n]->vno == verse) { |
| 915 | return(staff_p->syls_p[n]); |
| 916 | } |
| 917 | } |
| 918 | return(0); |
| 919 | } |
| 920 | \f |
| 921 | |
| 922 | /* Given a syl and related info, return the default time and place at which to |
| 923 | * end an underscore from that syl, for this measure. If there is a |
| 924 | * non-space syl later in the measure, this will be right before that syl, |
| 925 | * otherwise right before the bar line. |
| 926 | */ |
| 927 | |
| 928 | static RATIONAL |
| 929 | default_end(mll_p, syl_p, start_time, end_p) |
| 930 | |
| 931 | struct MAINLL *mll_p; /* the STAFF pointing to the syl */ |
| 932 | struct GRPSYL *syl_p; /* start looking from the syl */ |
| 933 | RATIONAL start_time; /* syl is already this far into measure */ |
| 934 | double *end_p; /* X value at which to end underscore is |
| 935 | * returned via this pointer */ |
| 936 | |
| 937 | { |
| 938 | struct GRPSYL *grp_p; |
| 939 | RATIONAL end_time; /* return value */ |
| 940 | |
| 941 | if (syl_p == 0) { |
| 942 | /* No syllable for current verse/place in current measure. |
| 943 | * Time signature may not be up to date, so add up the |
| 944 | * time of voice 1, which we know exists. |
| 945 | */ |
| 946 | end_time = start_time; |
| 947 | for (grp_p = mll_p->u.staff_p->groups_p[0]; grp_p != 0; |
| 948 | grp_p = grp_p->next) { |
| 949 | end_time = radd(end_time, grp_p->fulltime); |
| 950 | } |
| 951 | } |
| 952 | else { |
| 953 | /* Go forward in the syl list, finding where the next non-space |
| 954 | * syllable is, if there is one in the current measure, |
| 955 | * otherwise find the end of the measure. |
| 956 | * Save the time and location of this. |
| 957 | */ |
| 958 | end_time = radd(start_time, syl_p->fulltime); |
| 959 | for (grp_p = syl_p->next; grp_p != 0; grp_p = grp_p->next) { |
| 960 | if (grp_p->grpcont == GC_SPACE) { |
| 961 | /* Underscore continues through "space" syls */ |
| 962 | end_time = radd(end_time, grp_p->fulltime); |
| 963 | continue; |
| 964 | } |
| 965 | else { |
| 966 | /* We have found the syllable |
| 967 | * at which the underscore |
| 968 | * from the previous syllable ends */ |
| 969 | break; |
| 970 | } |
| 971 | } |
| 972 | } |
| 973 | |
| 974 | /* If a next syl was found, set end to near its west. |
| 975 | * Most likely, we will discover later we need to stop the underscore |
| 976 | * earlier than this, but if the user is using underscore in a strange |
| 977 | * way, like on a single long note rather than a melissma, |
| 978 | * we'll use this as the default place to end the underscore.*/ |
| 979 | if (grp_p != 0) { |
| 980 | *end_p = grp_p->c[AW] - Stepsize; |
| 981 | } |
| 982 | else { |
| 983 | /* The ending syllable (if any) is not in the current measure. |
| 984 | * So for now we set the end to near the west of the bar line. |
| 985 | * Note that end_time will have added up to |
| 986 | * the full measure duration in this case. |
| 987 | */ |
| 988 | for ( ; mll_p != 0; mll_p = mll_p->next) { |
| 989 | if (mll_p->str == S_BAR) { |
| 990 | *end_p = mll_p->u.bar_p->c[AW] - Stepsize; |
| 991 | break; |
| 992 | } |
| 993 | } |
| 994 | if (mll_p == 0) { |
| 995 | pfatal("underscore: failed to find next bar"); |
| 996 | } |
| 997 | } |
| 998 | return(end_time); |
| 999 | } |
| 1000 | \f |
| 1001 | |
| 1002 | /* Given a bar, see if it is a bar that might force stopping an extender, |
| 1003 | * and return YES, if so. If nextsyl_p_p is non-null, it also attempts |
| 1004 | * to fill that in with a pointer to the next "logical" syllable. |
| 1005 | * (Usually the next syllable, but at the end of a repeat it would |
| 1006 | * be the first syllable in the repeated section). |
| 1007 | * If it can't figure out the correct syllable, it fills in null. |
| 1008 | */ |
| 1009 | |
| 1010 | static int |
| 1011 | bar_ends_extender(bar_p, mll_p, staffno, verse, place, nextsyl_p_p) |
| 1012 | |
| 1013 | struct BAR *bar_p; |
| 1014 | struct MAINLL *mll_p; /* points to a BAR or CLEFSIG*/ |
| 1015 | int staffno; |
| 1016 | int verse; |
| 1017 | int place; |
| 1018 | struct GRPSYL **nextsyl_p_p; /* If this is non-zero, and we can deduce |
| 1019 | * the next "logical" syl, the pointed to value |
| 1020 | * will be updated to point to that next syl, |
| 1021 | * else will be zero. */ |
| 1022 | |
| 1023 | { |
| 1024 | int bartype; |
| 1025 | |
| 1026 | bartype = bar_p->bartype; |
| 1027 | if (bartype == RESTART) { |
| 1028 | /* We shouldn't continue an extender over a restart. |
| 1029 | * The "next" logical measure is probably the |
| 1030 | * target of a D.S. or a D.C. |
| 1031 | * But we don't attempt to parse |
| 1032 | * STUFF strings to know such things. |
| 1033 | * So we say the extender ends here, |
| 1034 | * but we don't know what the "next" measure is. |
| 1035 | */ |
| 1036 | if (nextsyl_p_p != 0) { |
| 1037 | *nextsyl_p_p = 0; |
| 1038 | } |
| 1039 | return(YES); |
| 1040 | } |
| 1041 | |
| 1042 | if (bartype == REPEATEND || bartype == REPEATBOTH) { |
| 1043 | if (nextsyl_p_p == 0) { |
| 1044 | return(YES); |
| 1045 | } |
| 1046 | |
| 1047 | /* This ends the extender. The next logical measure |
| 1048 | * is at the beginning of the repeat. */ |
| 1049 | for (mll_p = mll_p->prev; mll_p != 0; mll_p = mll_p->prev) { |
| 1050 | if (mll_p->str == S_BAR && |
| 1051 | (mll_p->u.bar_p->bartype |
| 1052 | == REPEATSTART || |
| 1053 | mll_p->u.bar_p->bartype |
| 1054 | == REPEATBOTH)) { |
| 1055 | mll_p = mll_p->next; |
| 1056 | break; |
| 1057 | } |
| 1058 | } |
| 1059 | if (mll_p == 0) { |
| 1060 | /* repeatstart is implicit at beginning of song */ |
| 1061 | mll_p = Mainllhc_p; |
| 1062 | } |
| 1063 | for ( ; mll_p != 0; mll_p = mll_p->next) { |
| 1064 | if (mll_p->str == S_BAR) { |
| 1065 | /* staff doesn't exist in this measure */ |
| 1066 | *nextsyl_p_p = 0; |
| 1067 | return(YES); |
| 1068 | } |
| 1069 | if (mll_p->str == S_STAFF && mll_p->u.staff_p->staffno |
| 1070 | == staffno) { |
| 1071 | *nextsyl_p_p = find_verse_place( |
| 1072 | mll_p->u.staff_p, verse, place); |
| 1073 | return(YES); |
| 1074 | } |
| 1075 | } |
| 1076 | } |
| 1077 | |
| 1078 | if (mll_p->u.bar_p->endingloc == STARTITEM) { |
| 1079 | /* If this is the start of a second or subsequent ending, |
| 1080 | * this ends the extender. This is the case if the previous |
| 1081 | * bar was a STARTITEM on INITEM. But apparently there |
| 1082 | * isn't a repeat ending here, or we would have hit the |
| 1083 | * bartype check for that. So it is too hard to try to deduce |
| 1084 | * the next logical syllable. */ |
| 1085 | for (mll_p = mll_p->prev; mll_p != 0; mll_p = mll_p->prev) { |
| 1086 | if (mll_p->str == S_BAR) { |
| 1087 | if (mll_p->u.bar_p->endingloc == STARTITEM || |
| 1088 | mll_p->u.bar_p->endingloc |
| 1089 | == INITEM) { |
| 1090 | if (nextsyl_p_p != 0) { |
| 1091 | *nextsyl_p_p = 0; |
| 1092 | } |
| 1093 | return(YES); |
| 1094 | } |
| 1095 | break; |
| 1096 | } |
| 1097 | } |
| 1098 | } |
| 1099 | |
| 1100 | return(NO); |
| 1101 | } |
| 1102 | \f |
| 1103 | |
| 1104 | /* Actually print an extender (dash or underscore) */ |
| 1105 | |
| 1106 | static void |
| 1107 | pr_extender(ch, start, end, y, font, size) |
| 1108 | |
| 1109 | int ch; /* dash or underscore */ |
| 1110 | double start; /* where to start printing */ |
| 1111 | double end; /* where to end printing */ |
| 1112 | double y; /* y coordinate */ |
| 1113 | int font; /* font to use for dash */ |
| 1114 | int size; /* size to use for dash */ |
| 1115 | |
| 1116 | { |
| 1117 | if (ch == '-') { |
| 1118 | double dashwidth; |
| 1119 | char dashstring[4]; |
| 1120 | |
| 1121 | dashwidth = width(font, size, '-'); |
| 1122 | |
| 1123 | /* generate the internal string format of a dash */ |
| 1124 | /* can't use dash_string function here since that also |
| 1125 | * deals with ~ which is okay for stuff but not lyrics */ |
| 1126 | dashstring[0] = (char) font; |
| 1127 | dashstring[1] = (char) size; |
| 1128 | dashstring[2] = '-'; |
| 1129 | dashstring[3] = '\0'; |
| 1130 | |
| 1131 | if ( (end - start) < (15.0 * dashwidth) ) { |
| 1132 | /* not much space, so find midpoint of |
| 1133 | * available distance and put dash there */ |
| 1134 | pr_string(start + ((end - start) / 2.0) |
| 1135 | - (dashwidth / 2.0), |
| 1136 | y, dashstring, J_LEFT, |
| 1137 | (char *) 0, -1); |
| 1138 | } |
| 1139 | else { |
| 1140 | int numdashes; /* how many dashes to print */ |
| 1141 | double spacebetween; /* between dashes */ |
| 1142 | |
| 1143 | /* Lots of space, so will need to print multiple dashes. |
| 1144 | * Figure out how to spread out */ |
| 1145 | numdashes = (int) ((end - start) / (8.0 * dashwidth)); |
| 1146 | spacebetween = ((end - start) - (dashwidth * numdashes)) |
| 1147 | / numdashes; |
| 1148 | |
| 1149 | for ( ; numdashes > 0; numdashes--) { |
| 1150 | pr_string(start + |
| 1151 | (numdashes - 0.5) * spacebetween |
| 1152 | + ((numdashes - 1.0) * dashwidth), |
| 1153 | y, dashstring, J_LEFT, |
| 1154 | (char *) 0, -1); |
| 1155 | } |
| 1156 | } |
| 1157 | } |
| 1158 | else { |
| 1159 | /* if long enough to bother drawing underscore, draw it */ |
| 1160 | if (end - start > Stepsize) { |
| 1161 | /* Note: line width probably really ought to |
| 1162 | * be scaled based on the lyric size, but unless |
| 1163 | * somebody uses really huge or really tiny lyrics, |
| 1164 | * a normal line width looks good enough, |
| 1165 | * so we just go with that. |
| 1166 | */ |
| 1167 | do_linetype(L_NORMAL); |
| 1168 | draw_line(start, y, end, y); |
| 1169 | } |
| 1170 | } |
| 1171 | } |
| 1172 | \f |
| 1173 | |
| 1174 | /* Return YES if last character of syllable is an underscore or dash, |
| 1175 | * NO if it isn't. |
| 1176 | */ |
| 1177 | |
| 1178 | int |
| 1179 | has_extender(syl) |
| 1180 | |
| 1181 | char *syl; /* the syllable to check */ |
| 1182 | |
| 1183 | { |
| 1184 | switch (last_char(syl)) { |
| 1185 | |
| 1186 | case '_': |
| 1187 | case '-': |
| 1188 | return(YES); |
| 1189 | |
| 1190 | default: |
| 1191 | return(NO); |
| 1192 | } |
| 1193 | } |
| 1194 | \f |
| 1195 | |
| 1196 | /* Return last character in a string. |
| 1197 | * If last character is a music character, |
| 1198 | * or the string is null, return null. |
| 1199 | */ |
| 1200 | |
| 1201 | int |
| 1202 | last_char(str) |
| 1203 | |
| 1204 | char *str; /* return last character in this string */ |
| 1205 | |
| 1206 | { |
| 1207 | int font, size; |
| 1208 | int ch; /* current character in string */ |
| 1209 | int last_font = FONT_UNKNOWN; /* font of last character */ |
| 1210 | int last_ch = '\0'; |
| 1211 | |
| 1212 | |
| 1213 | if (str == (char *) 0) { |
| 1214 | return('\0'); |
| 1215 | } |
| 1216 | |
| 1217 | font = str[0]; |
| 1218 | size = str[1]; |
| 1219 | |
| 1220 | /* keep track of each character. When we hit |
| 1221 | * end of string, return the last character we saw */ |
| 1222 | for ( str += 2; (ch = next_str_char(&str, &font, &size)) != 0; ) { |
| 1223 | last_font = font; |
| 1224 | last_ch = ch; |
| 1225 | } |
| 1226 | /* music characters don't count */ |
| 1227 | if (IS_MUSIC_FONT(last_font)) { |
| 1228 | return('\0'); |
| 1229 | } |
| 1230 | return (last_ch & 0xff); |
| 1231 | } |
| 1232 | \f |
| 1233 | |
| 1234 | /* See if an underscore or dash will need to be carried to the following score. |
| 1235 | * If so, add an appropriate "syllable" at the beginning of that score */ |
| 1236 | |
| 1237 | void |
| 1238 | cont_extender(mll_p, sylplace, verseno) |
| 1239 | |
| 1240 | struct MAINLL *mll_p; /* the syllable is hanging off of this STAFF */ |
| 1241 | int sylplace; /* PL_ABOVE, etc */ |
| 1242 | int verseno; /* verse number */ |
| 1243 | |
| 1244 | { |
| 1245 | struct GRPSYL *syl_p; /* walk through GRPSYL list */ |
| 1246 | struct GRPSYL *last_non_space_p; |
| 1247 | int last_ch; /* last character of syllable */ |
| 1248 | int font; /* of syllable */ |
| 1249 | int size; /* of syllable */ |
| 1250 | |
| 1251 | |
| 1252 | if (mll_p->str != S_STAFF) { |
| 1253 | pfatal("cont_extender called with wrong argument"); |
| 1254 | } |
| 1255 | |
| 1256 | /* Find the actual syl grpsyl that is the last on the score */ |
| 1257 | syl_p = find_verse_place(mll_p->u.staff_p, verseno, sylplace); |
| 1258 | |
| 1259 | if (syl_p == 0) { |
| 1260 | pfatal("cont_extender called without any syllable"); |
| 1261 | } |
| 1262 | |
| 1263 | /* Find the final non-space syllable in the list */ |
| 1264 | last_non_space_p = 0; |
| 1265 | for ( ; syl_p != 0; syl_p = syl_p->next) { |
| 1266 | if (syl_p->grpcont != GC_SPACE) { |
| 1267 | last_non_space_p = syl_p; |
| 1268 | } |
| 1269 | } |
| 1270 | |
| 1271 | if (last_non_space_p == 0) { |
| 1272 | pfatal("cont_extender couldn't find non-space syllable"); |
| 1273 | } |
| 1274 | |
| 1275 | last_ch = last_char(last_non_space_p->syl); |
| 1276 | if (last_ch != '-' && last_ch != '_') { |
| 1277 | pfatal("cont_extender called on syl without extender"); |
| 1278 | } |
| 1279 | |
| 1280 | /* See if will carry over */ |
| 1281 | if (spread_extender(last_non_space_p, mll_p, verseno, sylplace, NO) |
| 1282 | == YES) { |
| 1283 | |
| 1284 | /* determine proper font/size of |
| 1285 | * carried over dash/underscore |
| 1286 | * based on font/size at end of syllable */ |
| 1287 | end_fontsize(last_non_space_p->syl, &font, &size); |
| 1288 | |
| 1289 | /* insert the syllable on next score */ |
| 1290 | insert_carryover_syllable(mll_p, |
| 1291 | last_non_space_p->staffno, sylplace, |
| 1292 | verseno, |
| 1293 | (last_ch == '-' ? "-" : "_"), |
| 1294 | font, size); |
| 1295 | } |
| 1296 | } |
| 1297 | \f |
| 1298 | |
| 1299 | /* A dash or underscore needs to be carried over to the following score. |
| 1300 | * Search forward for the appropriate STAFF. If there is already a lyric |
| 1301 | * there for the sylplace and verseno, if its first syllable is a space, |
| 1302 | * change it to a dash or underscore as appropriate. |
| 1303 | * If there is no lyric in that measure for the sylplace and verseno, |
| 1304 | * insert a measure long syllable of the appropriate type. |
| 1305 | * If there is no STAFF of the proper number after a FEED, assume we are |
| 1306 | * at the end of the piece or of visibility of the staff, and do nothing. |
| 1307 | * If there is already a syllable, leave it as is. |
| 1308 | */ |
| 1309 | |
| 1310 | |
| 1311 | static void |
| 1312 | insert_carryover_syllable(mll_p, staffno, sylplace, verseno, dash_or_underscore, |
| 1313 | font, size) |
| 1314 | |
| 1315 | struct MAINLL *mll_p; /* points to staff info */ |
| 1316 | int staffno; /* staff number */ |
| 1317 | int sylplace; /* PL_ABOVE, etc */ |
| 1318 | int verseno; /* verse number */ |
| 1319 | char *dash_or_underscore; /* "-" or "_" */ |
| 1320 | int font; /* font and size to use for dash or underscore */ |
| 1321 | int size; |
| 1322 | |
| 1323 | { |
| 1324 | struct STAFF *staff_p; /* add syllable to this staff */ |
| 1325 | struct CHORD *chord_p; /* chord syllables goes with */ |
| 1326 | int v; /* verse index */ |
| 1327 | float begin_x; /* where to start carryover syllable */ |
| 1328 | |
| 1329 | |
| 1330 | /* search forward for FEED */ |
| 1331 | for ( ; mll_p != (struct MAINLL *) 0; mll_p = mll_p->next) { |
| 1332 | if (IS_CLEFSIG_FEED(mll_p)) { |
| 1333 | break; |
| 1334 | } |
| 1335 | } |
| 1336 | |
| 1337 | if (mll_p == (struct MAINLL *) 0) { |
| 1338 | return; |
| 1339 | } |
| 1340 | |
| 1341 | /* The AE coordinates of syllable groups |
| 1342 | * have already been set, but we need to have |
| 1343 | * this one set for the underscore/dash syllable being added. So deduce |
| 1344 | * where it should be using the pseudo-bar */ |
| 1345 | if ((mll_p = mll_p->next) == (struct MAINLL *) 0) { |
| 1346 | return; |
| 1347 | } |
| 1348 | if (mll_p->str == S_CLEFSIG) { |
| 1349 | begin_x = mll_p->u.clefsig_p->bar_p->c[AE] + STDPAD; |
| 1350 | } |
| 1351 | else { |
| 1352 | /* setting begin_x is just to shut up compilers that erroneously |
| 1353 | * think it could be used without being set. */ |
| 1354 | begin_x = 0.0; |
| 1355 | pfatal("no clefsig after feed"); |
| 1356 | } |
| 1357 | |
| 1358 | /* silence compilers that think chord_p might not be set */ |
| 1359 | chord_p = (struct CHORD *) 0; |
| 1360 | |
| 1361 | /* search forward for STAFF of interest, and save CHORD info */ |
| 1362 | for ( mll_p = mll_p->next; mll_p != (struct MAINLL *) 0; |
| 1363 | mll_p = mll_p->next) { |
| 1364 | |
| 1365 | if (mll_p->str == S_CHHEAD) { |
| 1366 | chord_p = mll_p->u.chhead_p->ch_p; |
| 1367 | } |
| 1368 | else if (mll_p->str == S_STAFF) { |
| 1369 | if (mll_p->u.staff_p->staffno == staffno) { |
| 1370 | break; |
| 1371 | } |
| 1372 | } |
| 1373 | } |
| 1374 | |
| 1375 | /* see if has syllable of specified place and verse */ |
| 1376 | if (mll_p != (struct MAINLL *) 0) { |
| 1377 | |
| 1378 | staff_p = mll_p->u.staff_p; |
| 1379 | for (v = 0; v < staff_p->nsyllists; v++) { |
| 1380 | |
| 1381 | if (staff_p->sylplace[v] == sylplace && |
| 1382 | staff_p->syls_p[v]->vno == verseno) { |
| 1383 | |
| 1384 | /* are lyrics in this measure. See if first |
| 1385 | * syllable is a space. If so, replace with |
| 1386 | * a dash. Otherwise we are done */ |
| 1387 | if (staff_p->syls_p[v]->syl == (char *) 0) { |
| 1388 | staff_p->syls_p[v]->syl = |
| 1389 | copy_string(dash_or_underscore, |
| 1390 | font, size); |
| 1391 | /* no longer a "space" syllable */ |
| 1392 | staff_p->syls_p[v]->grpcont = GC_NOTES; |
| 1393 | } |
| 1394 | return; |
| 1395 | } |
| 1396 | } |
| 1397 | |
| 1398 | /* no lyrics in first measure on next score for this |
| 1399 | * verse/place. Need to insert one */ |
| 1400 | add_syllable(staff_p, sylplace, verseno, |
| 1401 | dash_or_underscore, font, size, |
| 1402 | begin_x, chord_p); |
| 1403 | } |
| 1404 | } |
| 1405 | \f |
| 1406 | |
| 1407 | /* Add a dash or underscore syllable to list of lyrics. Need to alloc new |
| 1408 | * space for the sylplace and syls_p arrays, copy the existing data into |
| 1409 | * them, adding the new syllable at the proper place (sorted by verseno), |
| 1410 | * then free the old arrays */ |
| 1411 | |
| 1412 | static void |
| 1413 | add_syllable(staff_p, sylplace, verseno, dash_or_underscore, font, size, |
| 1414 | begin_x, chord_p) |
| 1415 | |
| 1416 | struct STAFF *staff_p; /* add syllable to this staff */ |
| 1417 | int sylplace; /* PL_ABOVE, etc */ |
| 1418 | int verseno; |
| 1419 | char *dash_or_underscore; /* "-" or "_" */ |
| 1420 | int font; |
| 1421 | int size; |
| 1422 | double begin_x; /* where syllable is to start */ |
| 1423 | struct CHORD *chord_p; /* what chord to attach to */ |
| 1424 | |
| 1425 | { |
| 1426 | short *new_sylplace; /* new, expanded sylplace array */ |
| 1427 | struct GRPSYL **new_syls_p; /* new, expanded syls_p array */ |
| 1428 | int v; /* verse index */ |
| 1429 | int insert_index; /* where to put in new arrays */ |
| 1430 | int inserted; /* 0 if haven't found where to insert |
| 1431 | * yet, 1 if we have. This is then the |
| 1432 | * difference between the index of the |
| 1433 | * original arrays and where the copy |
| 1434 | * goes in the new arrays. Since it's |
| 1435 | * used in array subscript calculation |
| 1436 | * we can't use YES and NO here */ |
| 1437 | |
| 1438 | |
| 1439 | /* alloc arrays that are one larger than the current arrays */ |
| 1440 | MALLOCA(short, new_sylplace, staff_p->nsyllists + 1); |
| 1441 | MALLOCA(struct GRPSYL *, new_syls_p, staff_p->nsyllists + 1); |
| 1442 | |
| 1443 | /* now copy and insert */ |
| 1444 | insert_index = staff_p->nsyllists; |
| 1445 | for (inserted = v = 0; v < staff_p->nsyllists; v++) { |
| 1446 | if (insert_index > v && staff_p->syls_p[v]->vno > verseno) { |
| 1447 | /* insert here */ |
| 1448 | insert_index = v; |
| 1449 | inserted = 1; |
| 1450 | } |
| 1451 | |
| 1452 | new_sylplace[v + inserted] = staff_p->sylplace[v]; |
| 1453 | new_syls_p[v + inserted] = staff_p->syls_p[v]; |
| 1454 | } |
| 1455 | |
| 1456 | /* alloc and fill in the new GRPSYL */ |
| 1457 | new_sylplace[insert_index] = (short) sylplace; |
| 1458 | new_syls_p[insert_index] = newGRPSYL(GS_SYLLABLE); |
| 1459 | new_syls_p[insert_index]->syl = copy_string(dash_or_underscore, |
| 1460 | font, size); |
| 1461 | new_syls_p[insert_index]->inputlineno = -1; |
| 1462 | new_syls_p[insert_index]->basictime = -1; |
| 1463 | new_syls_p[insert_index]->is_meas = YES; |
| 1464 | new_syls_p[insert_index]->fulltime = Score.time; |
| 1465 | new_syls_p[insert_index]->staffno = staff_p->staffno; |
| 1466 | new_syls_p[insert_index]->vno = (short) verseno; |
| 1467 | /* X coords of normal syllables already set, so have to set for |
| 1468 | * this special syllable here */ |
| 1469 | new_syls_p[insert_index]->c[AE] = begin_x |
| 1470 | + strwidth(new_syls_p[insert_index]->syl); |
| 1471 | new_syls_p[insert_index]->c[AW] = begin_x; |
| 1472 | new_syls_p[insert_index]->c[AX] = begin_x; |
| 1473 | |
| 1474 | /* now have one one list of syllables */ |
| 1475 | (staff_p->nsyllists)++; |
| 1476 | |
| 1477 | /* free old arrays if non-null */ |
| 1478 | if (staff_p->sylplace != (short *) 0) { |
| 1479 | FREE(staff_p->sylplace); |
| 1480 | } |
| 1481 | if (staff_p->syls_p != (struct GRPSYL **) 0) { |
| 1482 | FREE(staff_p->syls_p); |
| 1483 | } |
| 1484 | |
| 1485 | /* now link up the new arrays */ |
| 1486 | staff_p->sylplace = new_sylplace; |
| 1487 | staff_p->syls_p = new_syls_p; |
| 1488 | |
| 1489 | /* add to appropriate chord */ |
| 1490 | stitch_syl_into_chord(chord_p, new_syls_p[insert_index]); |
| 1491 | } |
| 1492 | \f |
| 1493 | |
| 1494 | /* Given a syllable and chord to attach it to, attach it */ |
| 1495 | /* Strictly speaking, this function probably isn't necessary, since I think |
| 1496 | * all use of the CHORD struct has already been done before this function is |
| 1497 | * called, but it's probably good to do anyway on general principles, in case |
| 1498 | * some day the CHORDs are looked at later */ |
| 1499 | |
| 1500 | static void |
| 1501 | stitch_syl_into_chord(chord_p, syl_gs_p) |
| 1502 | |
| 1503 | struct CHORD *chord_p; /* add to this chord */ |
| 1504 | struct GRPSYL *syl_gs_p; /* add this syllable */ |
| 1505 | |
| 1506 | { |
| 1507 | struct GRPSYL *gs_p; /* walk through chord */ |
| 1508 | |
| 1509 | |
| 1510 | /* go down chord list */ |
| 1511 | for (gs_p = chord_p->gs_p; gs_p->gs_p != (struct GRPSYL *) 0; |
| 1512 | gs_p = gs_p->gs_p) { |
| 1513 | |
| 1514 | /* if next grpsyl in chord has staffno < staffno of syl to add, |
| 1515 | * keep going */ |
| 1516 | if (gs_p->gs_p->staffno < syl_gs_p->staffno) { |
| 1517 | continue; |
| 1518 | } |
| 1519 | |
| 1520 | /* if next grpsyl in chord had staffno > staffno of syl to add, |
| 1521 | * put it here */ |
| 1522 | if (gs_p->gs_p->staffno > syl_gs_p->staffno) { |
| 1523 | /* found where to insert */ |
| 1524 | break; |
| 1525 | } |
| 1526 | |
| 1527 | /* If here, must be same staffno. |
| 1528 | * Keep going until find syllable with larger vno. */ |
| 1529 | if (gs_p->gs_p->grpsyl == GS_GROUP) { |
| 1530 | continue; |
| 1531 | } |
| 1532 | |
| 1533 | if (gs_p->gs_p->vno > syl_gs_p->vno) { |
| 1534 | /* found where to insert */ |
| 1535 | break; |
| 1536 | } |
| 1537 | } |
| 1538 | |
| 1539 | /* insert syllable */ |
| 1540 | syl_gs_p->gs_p = gs_p->gs_p; |
| 1541 | gs_p->gs_p = syl_gs_p; |
| 1542 | } |