Commit | Line | Data |
---|---|---|
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 | ||
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 | } |