chiark / gitweb /
Merge branch 'arkkra' into shiny
[mup] / mup / mup / undrscre.c
CommitLineData
69695f33
MW
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
12static double end_dashes P((struct MAINLL *mll_p, struct GRPSYL *syl_p,
13 int verse, int place, int *carryover_p));
14static double end_underscore P((struct MAINLL *mll_p, struct GRPSYL *syl_p,
15 int verse, int place, int *carryover_p));
16static double endx P((struct GRPSYL *last_grp_p, double end));
17static int has_above_lyr P((struct MAINLL *mll_p, RATIONAL begin_time,
18 struct GRPSYL *group_p, int verse));
19static int voice_is_above P((int v1, int v2));
20static struct GRPSYL *find_verse_place P((struct STAFF *staff_p,
21 int verse, int place));
22static RATIONAL default_end P((struct MAINLL *mll_p, struct GRPSYL *syl_p,
23 RATIONAL start_time, double *end_p));
24static 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));
27static void pr_extender P((int ch, double start, double end, double y,
28 int font, int size));
29static 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));
32static 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));
35static 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
68int
69spread_extender(syl_p, mll_p, verse, sylplace, really_print)
70
71struct GRPSYL *syl_p; /* current syllable */
72struct MAINLL *mll_p; /* which MAINLL struct it's hanging off of */
73int verse; /* verse number */
74int sylplace; /* PL_ABOVE, etc */
75int 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
172static double
173end_dashes(mll_p, syl_p, verse, place, carryover_p)
174
175struct MAINLL *mll_p; /* points to STAFF containing the syl with dash */
176struct GRPSYL *syl_p; /* this is the syllable with dash */
177int verse; /* which verse the syl_p is for */
178int place; /* a PL_* value for where the lyric is */
179int *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
269static double
270end_underscore(mll_p, syl_p, verse, place, carryover_p)
271
272struct MAINLL *mll_p; /* points to STAFF containing the syl with underscore */
273struct GRPSYL *syl_p; /* this is the syllable with underscore */
274int verse; /* which verse the syl_p is for */
275int place; /* a PL_* value for where the lyric is */
276int *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
649static double
650endx(last_grp_p, end)
651
652struct GRPSYL *last_grp_p; /* if != 0, use east edge of notes of this */
653double 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
717static int
718has_above_lyr(mll_p, begin_time, group_p, verse)
719
720struct MAINLL *mll_p; /* points to syl's STAFF */
721RATIONAL begin_time;
722struct GRPSYL *group_p; /* see if there a lyric above this group */
723int 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
872static int
873voice_is_above(v1, v2)
874
875int v1;
876int 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
902static struct GRPSYL *
903find_verse_place(staff_p, verse, place)
904
905struct STAFF *staff_p;
906int verse;
907int 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
928static RATIONAL
929default_end(mll_p, syl_p, start_time, end_p)
930
931struct MAINLL *mll_p; /* the STAFF pointing to the syl */
932struct GRPSYL *syl_p; /* start looking from the syl */
933RATIONAL start_time; /* syl is already this far into measure */
934double *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
1010static int
1011bar_ends_extender(bar_p, mll_p, staffno, verse, place, nextsyl_p_p)
1012
1013struct BAR *bar_p;
1014struct MAINLL *mll_p; /* points to a BAR or CLEFSIG*/
1015int staffno;
1016int verse;
1017int place;
1018struct 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
1106static void
1107pr_extender(ch, start, end, y, font, size)
1108
1109int ch; /* dash or underscore */
1110double start; /* where to start printing */
1111double end; /* where to end printing */
1112double y; /* y coordinate */
1113int font; /* font to use for dash */
1114int 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
1178int
1179has_extender(syl)
1180
1181char *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
1201int
1202last_char(str)
1203
1204char *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
1237void
1238cont_extender(mll_p, sylplace, verseno)
1239
1240struct MAINLL *mll_p; /* the syllable is hanging off of this STAFF */
1241int sylplace; /* PL_ABOVE, etc */
1242int 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
1311static void
1312insert_carryover_syllable(mll_p, staffno, sylplace, verseno, dash_or_underscore,
1313 font, size)
1314
1315struct MAINLL *mll_p; /* points to staff info */
1316int staffno; /* staff number */
1317int sylplace; /* PL_ABOVE, etc */
1318int verseno; /* verse number */
1319char *dash_or_underscore; /* "-" or "_" */
1320int font; /* font and size to use for dash or underscore */
1321int 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
1412static void
1413add_syllable(staff_p, sylplace, verseno, dash_or_underscore, font, size,
1414 begin_x, chord_p)
1415
1416struct STAFF *staff_p; /* add syllable to this staff */
1417int sylplace; /* PL_ABOVE, etc */
1418int verseno;
1419char *dash_or_underscore; /* "-" or "_" */
1420int font;
1421int size;
1422double begin_x; /* where syllable is to start */
1423struct 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
1500static void
1501stitch_syl_into_chord(chord_p, syl_gs_p)
1502
1503struct CHORD *chord_p; /* add to this chord */
1504struct 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}