Commit | Line | Data |
---|---|---|
69695f33 MW |
1 | |
2 | /* Copyright (c) 1995, 1997, 1998, 1999, 2000, 2001, 2002, 2004, 2005, 2006 by Arkkra Enterprises */ | |
3 | /* All rights reserved */ | |
4 | ||
5 | /* functions called by the parse phase to deal with lyrics */ | |
6 | ||
7 | #include "defines.h" | |
8 | #include "structs.h" | |
9 | #include "globals.h" | |
10 | ||
11 | ||
12 | /* information about a measure-worth of lyrics */ | |
13 | struct LYRINFO { | |
14 | short place; /* PL_ABOVE, etc */ | |
15 | short vno; /* verse number */ | |
16 | struct GRPSYL *gs_p; /* the lyrics themselves */ | |
17 | struct LYRINFO *next; /* for linked list of other verses on the | |
18 | * same staff */ | |
19 | }; | |
20 | ||
21 | /* current font/size for each staff/verse/place combination */ | |
22 | struct LYRFONTSIZE { | |
23 | short staffno; | |
24 | short verse; | |
25 | char place; /* PL_ABOVE, etc */ | |
26 | char font; | |
27 | char size; | |
28 | char all; /* YES if "above all" or "below all". | |
29 | * In that case, the staffno is | |
30 | * irrelevant */ | |
31 | struct LYRFONTSIZE *next; /* linked list */ | |
32 | }; | |
33 | ||
34 | /* we keep the font/size info independently for each staff/verse/place combo | |
35 | * and carry it forward from measure to measure. Info is stored here */ | |
36 | struct LYRFONTSIZE *Lyrfontsizeinfo_p [MAXSTAFFS + 1]; | |
37 | ||
38 | /* for each staff, keep a list of all the GRPSYL lyric lists that will be | |
39 | * associated with that staff. */ | |
40 | static struct LYRINFO *Lyr_tbl[MAXSTAFFS + 1]; | |
41 | ||
42 | /* need to keep a list of all verse numbers ever used, for setting Maxverses */ | |
43 | static struct RANGELIST *Above_vnumbers_used; | |
44 | static struct RANGELIST *Below_vnumbers_used; | |
45 | static struct RANGELIST *Between_vnumbers_used; | |
46 | ||
47 | /* for auto-numbering verses, keep track of the last verse number used | |
48 | * for each staff/place */ | |
49 | static short Prev_verse_num[MAXSTAFFS+1][NUM_PLACE]; | |
50 | ||
51 | /* static function declarations */ | |
52 | static void free_lyrinfo P((struct LYRINFO *lyrinfo_p)); | |
53 | static void assoc_lyr2staff P((int staffno, int verse, struct GRPSYL *gs_p, | |
54 | char *lyrstring, int all, int place)); | |
55 | static struct LYRFONTSIZE *getlyrfontsize P((int staffno, int verse, | |
56 | int place, int all)); | |
57 | static void updlyrfontsize P((struct LYRFONTSIZE *lyrfontsize_p, | |
58 | int font, int size)); | |
59 | static char *next_syl P((char **sylstring_p, int *font_p, int *size_p, | |
60 | short *position_p, int staffno)); | |
61 | static void do_sylwidth P((char *lyrstring, float *wid_b4_syl_p, | |
62 | float *wid_real_syl_p, float *wid_after_syl_p, | |
63 | int compensating)); | |
64 | static void count_verses P((struct RANGELIST *used_p)); | |
65 | static void vno_used P((int vno)); | |
66 | \f | |
67 | ||
68 | /* given a range of verses, save the range for later use */ | |
69 | ||
70 | void | |
71 | lyr_verse(begin, end) | |
72 | ||
73 | int begin; /* first verse in range */ | |
74 | int end; /* last verse number in range */ | |
75 | ||
76 | { | |
77 | /* error check */ | |
78 | /* Note that -1 is a special value meaning "one more than previous." | |
79 | * Zero is also special, meaning "centered," but that doesn't | |
80 | * get handled by this function, since that doesn't need the error | |
81 | * checks that are done here, since the parser guarantees good values. | |
82 | * If a zero does get passed in, the user must have explicitly | |
83 | * specified it, which is a user error. | |
84 | */ | |
85 | if (begin < 1 && begin != -1) { | |
86 | yyerror("verse number must be >= 1"); | |
87 | return; | |
88 | } | |
89 | ||
90 | if (end < begin) { | |
91 | yyerror("end of verse range smaller than beginning"); | |
92 | return; | |
93 | } | |
94 | ||
95 | save_vno_range(begin, end); | |
96 | } | |
97 | \f | |
98 | ||
99 | /* once all the information about a measure-worth of lyrics has been | |
100 | * gathered, process it. Break up the lyrics string into syllables and | |
101 | * store them in the appropriate GRPSYL structs. Then clone the list as | |
102 | * many times as necessary for each staff/verse, and associate with | |
103 | * appropriate staffs. | |
104 | */ | |
105 | ||
106 | void | |
107 | proc_lyrics(grpsyl_p, lyrstring) | |
108 | ||
109 | struct GRPSYL *grpsyl_p; /* list of GRPSYLs with time values */ | |
110 | char *lyrstring; /* string containing the lyrics */ | |
111 | ||
112 | { | |
113 | struct RANGELIST *slist_p; /* walk through list of staffs */ | |
114 | struct RANGELIST *vlist_p; /* walk through list of verses */ | |
115 | int staffno; | |
116 | int verse; | |
117 | int place; | |
118 | ||
119 | ||
120 | if (grpsyl_p == (struct GRPSYL *) 0 || lyrstring == (char *) 0) { | |
121 | return; | |
122 | } | |
123 | ||
124 | debug(2, "proc_lyrics file=%s lineno=%d", grpsyl_p->inputfile, | |
125 | grpsyl_p->inputlineno); | |
126 | ||
127 | /* for each staff and verse being defined, clone the GRPSYL | |
128 | * list and associate with appropriate staff */ | |
129 | /* do each appropriate staff */ | |
130 | for (slist_p = Staffrange_p; slist_p != (struct RANGELIST *) 0; | |
131 | slist_p = slist_p->next) { | |
132 | place = (slist_p->place == PL_UNKNOWN ? PL_BELOW : slist_p->place); | |
133 | for (staffno = slist_p->begin; staffno <= slist_p->end; | |
134 | staffno++) { | |
135 | ||
136 | /* do each appropriate verse */ | |
137 | for (vlist_p = Vnorange_p; | |
138 | vlist_p != (struct RANGELIST *) 0; | |
139 | vlist_p = vlist_p->next) { | |
140 | ||
141 | for (verse = vlist_p->begin; | |
142 | verse <= vlist_p->end; | |
143 | verse++) { | |
144 | ||
145 | /* -1 means one more than previous */ | |
146 | if (verse == -1) { | |
147 | ||
148 | verse = Prev_verse_num[staffno][place] + 1; | |
149 | } | |
150 | Prev_verse_num[staffno][place] = verse; | |
151 | /* connect to proper staff */ | |
152 | assoc_lyr2staff(staffno, verse, | |
153 | grpsyl_p, lyrstring, | |
154 | slist_p->all, place); | |
155 | ||
156 | /* mark that we've use this verse # */ | |
157 | vno_used(verse); | |
158 | } | |
159 | } | |
160 | } | |
161 | } | |
162 | ||
163 | /* free the vno rangelist. Don't free the staff info yet, because | |
164 | * there may be more verses */ | |
165 | free_vnorange(); | |
166 | ||
167 | /* the lyrics string has been broken into syllables. Don't need | |
168 | * the original string anymore */ | |
169 | FREE(lyrstring); | |
170 | } | |
171 | \f | |
172 | ||
173 | /* connect a list of syllable to specified STAFF */ | |
174 | ||
175 | static void | |
176 | assoc_lyr2staff(staffno, verse, gs_p, lyrstring, all, place) | |
177 | ||
178 | int staffno; /* which staff lyrics belong to */ | |
179 | int verse; /* verse number of lyrics */ | |
180 | struct GRPSYL *gs_p; /* list of GRPSYLs with time information */ | |
181 | char *lyrstring; /* string of lyrics syllables in this measure/verse */ | |
182 | int all; /* YES if associated with "all" */ | |
183 | int place; /* PL_* */ | |
184 | ||
185 | { | |
186 | struct LYRINFO *new_p; /* to store info about | |
187 | * current staff/verse lyrics */ | |
188 | struct LYRINFO *lyrinfo_p; /* used when searching for | |
189 | * where to insert this verse */ | |
190 | struct LYRINFO **insert_place_p_p; /* address of where to add | |
191 | * lyric info when doing | |
192 | * insertion sort */ | |
193 | char *lyr_copy; /* copy of lyrics */ | |
194 | int font; | |
195 | int size; | |
196 | struct LYRFONTSIZE *lyrfontsize_p; /* info about font/size for | |
197 | * current staff/verse/place */ | |
198 | ||
199 | ||
200 | debug(4, "assoc_lyr2staff file=%s lineno=%d staffno=%d, verse=%d, all=%d, place=%d", | |
201 | gs_p->inputfile, gs_p->inputlineno, staffno, verse, | |
202 | all, place); | |
203 | ||
204 | if (staffno > Score.staffs) { | |
205 | l_yyerror(gs_p->inputfile, gs_p->inputlineno, | |
206 | "can't have lyrics for staff %d when there aren't that many staffs", | |
207 | staffno); | |
208 | return; | |
209 | } | |
210 | ||
211 | /* make a copy of the grpsyl list for this staff/verse */ | |
212 | gs_p = clone_gs_list(gs_p, NO); | |
213 | ||
214 | /* allocate space to save info, and fill it in */ | |
215 | CALLOC(LYRINFO, new_p, 1); | |
216 | new_p->vno = (short) verse; | |
217 | new_p->place = place; | |
218 | new_p->gs_p = gs_p; | |
219 | ||
220 | /* insertion sort into list of lyrics for this staff */ | |
221 | for (insert_place_p_p = & (Lyr_tbl[staffno]); | |
222 | *insert_place_p_p != (struct LYRINFO *) 0; | |
223 | insert_place_p_p = & ((*insert_place_p_p)->next) ) { | |
224 | ||
225 | lyrinfo_p = (*insert_place_p_p); | |
226 | ||
227 | if ( lyrinfo_p->vno > verse) { | |
228 | /* need to insert new one right before this one */ | |
229 | break; | |
230 | } | |
231 | ||
232 | if ( (lyrinfo_p->vno == verse) | |
233 | && (lyrinfo_p->place == new_p->place)) { | |
234 | l_yyerror(Curr_filename, yylineno, | |
235 | "verse %d, staff %d multiply defined", | |
236 | verse, staffno); | |
237 | return; | |
238 | } | |
239 | } | |
240 | new_p->next = *insert_place_p_p; | |
241 | *insert_place_p_p = new_p; | |
242 | ||
243 | /* we need to set font/size on a per-staff basis. That means we | |
244 | * have to make a temporary copy for each instance and get the | |
245 | * syllables each time */ | |
246 | lyrfontsize_p = getlyrfontsize(staffno, verse, Place, all); | |
247 | font = lyrfontsize_p->font; | |
248 | size = lyrfontsize_p->size; | |
249 | ||
250 | lyr_copy = lyrstring = copy_string(lyrstring + 2, font, size); | |
251 | ||
252 | /* get into internal format */ | |
253 | fix_string(lyrstring, font, size, Curr_filename, yylineno); | |
254 | ||
255 | /* skip past the font/size */ | |
256 | lyrstring += 2; | |
257 | ||
258 | /* fill in vno, staffno, and syllables */ | |
259 | for ( ; gs_p != (struct GRPSYL *) 0; gs_p = gs_p->next) { | |
260 | ||
261 | gs_p->staffno = (short) staffno; | |
262 | gs_p->vno = (short) verse; | |
263 | ||
264 | /* if this GRPSYL is a space, don't fill in a syllable */ | |
265 | if (gs_p->grpcont == GC_SPACE) { | |
266 | continue; | |
267 | } | |
268 | ||
269 | /* otherwise, find the next syllable, and store it in | |
270 | * the GRPSYL */ | |
271 | gs_p->syl = next_syl(&lyrstring, &font, &size, | |
272 | &(gs_p->sylposition), staffno); | |
273 | } | |
274 | ||
275 | /* keep track of font/size at end of measure in case we have more | |
276 | * lyrics in this same staff/verse/place on a later measure */ | |
277 | updlyrfontsize(lyrfontsize_p, font, size); | |
278 | ||
279 | /* skip over any trailing white space */ | |
280 | while (*lyrstring == ' ' || *lyrstring == '\t') { | |
281 | lyrstring++; | |
282 | } | |
283 | ||
284 | if (*lyrstring != '\0') { | |
285 | yyerror("too many syllables in string"); | |
286 | } | |
287 | ||
288 | /* the copy has been broken into syllables. Free the copy */ | |
289 | FREE(lyr_copy); | |
290 | } | |
291 | \f | |
292 | ||
293 | /* given a staffno, verse, and place, return (via pointer to struct of info) | |
294 | * the font and size that should be used */ | |
295 | ||
296 | static struct LYRFONTSIZE * | |
297 | getlyrfontsize(staffno, verse, place, all) | |
298 | ||
299 | int staffno; | |
300 | int verse; | |
301 | int place; | |
302 | int all; /* YES if associated with "all" */ | |
303 | ||
304 | { | |
305 | struct LYRFONTSIZE *lfs_p; /* walk through linked list */ | |
306 | ||
307 | ||
308 | /* if this staff/verse/place is on the list, use the values stored | |
309 | * there. */ | |
310 | for (lfs_p = Lyrfontsizeinfo_p [staffno]; | |
311 | lfs_p != (struct LYRFONTSIZE *) 0; | |
312 | lfs_p = lfs_p->next) { | |
313 | ||
314 | if (lfs_p->staffno == staffno && lfs_p->verse == verse | |
315 | && lfs_p->place == place && lfs_p->all == all) { | |
316 | return(lfs_p); | |
317 | } | |
318 | } | |
319 | ||
320 | /* wasn't on list yet. Add to list, using default values from SSV */ | |
321 | MALLOC(LYRFONTSIZE, lfs_p, 1); | |
322 | lfs_p->staffno = (short) staffno; | |
323 | lfs_p->verse = (short) verse; | |
324 | lfs_p->place = (char) place; | |
325 | lfs_p->all = (char) all; | |
326 | if (all == YES) { | |
327 | lfs_p->font = (char) (Score.lyricsfamily + Score.lyricsfont); | |
328 | lfs_p->size = (char) Score.lyricssize; | |
329 | } | |
330 | else { | |
331 | lfs_p->font = svpath(staffno, LYRICSFAMILY)->lyricsfamily | |
332 | + svpath(staffno, LYRICSFONT)->lyricsfont; | |
333 | lfs_p->size = svpath(staffno, LYRICSFONT)->lyricssize; | |
334 | } | |
335 | lfs_p->next = Lyrfontsizeinfo_p [ staffno ]; | |
336 | Lyrfontsizeinfo_p [ staffno ] = lfs_p; | |
337 | ||
338 | return(lfs_p); | |
339 | } | |
340 | \f | |
341 | ||
342 | /* update values of font/size for a given LYRFONTSIZE struct */ | |
343 | ||
344 | static void | |
345 | updlyrfontsize(lyrfontsize_p, font, size) | |
346 | ||
347 | struct LYRFONTSIZE *lyrfontsize_p; | |
348 | int font; | |
349 | int size; | |
350 | ||
351 | { | |
352 | lyrfontsize_p->font = (char) font; | |
353 | lyrfontsize_p->size = (char) size; | |
354 | } | |
355 | \f | |
356 | ||
357 | /* when user sets lyricsfont via an SSV, that overrides whatever fonts are | |
358 | * currently in effect, so change them. */ | |
359 | ||
360 | void | |
361 | setlyrfont(staffno, font) | |
362 | ||
363 | int staffno; | |
364 | int font; | |
365 | ||
366 | { | |
367 | int s; /* index through staffs */ | |
368 | struct LYRFONTSIZE *lfs_p; /* info about font/size */ | |
369 | ||
370 | ||
371 | if (Context == C_SCORE) { | |
372 | Context = C_STAFF; | |
373 | /* reset all staffs */ | |
374 | for (s = 1; s <= Score.staffs; s++) { | |
375 | setlyrfont(s, font); | |
376 | } | |
377 | Context = C_SCORE; | |
378 | } | |
379 | else { | |
380 | /* set all place/verse combinations of given staff */ | |
381 | for (lfs_p = Lyrfontsizeinfo_p [staffno]; | |
382 | lfs_p != (struct LYRFONTSIZE *) 0; | |
383 | lfs_p = lfs_p->next) { | |
384 | lfs_p->font = (lfs_p->all == YES ? Score.lyricsfamily | |
385 | + Score.lyricsfont | |
386 | : svpath(staffno, LYRICSFAMILY)->lyricsfamily | |
387 | + font); | |
388 | } | |
389 | } | |
390 | } | |
391 | \f | |
392 | ||
393 | /* when user sets lyricsize via an SSV, that overrides whatever fonts are | |
394 | * currently in effect, so change them. */ | |
395 | ||
396 | void | |
397 | setlyrsize(staffno, size) | |
398 | ||
399 | int staffno; | |
400 | int size; | |
401 | ||
402 | { | |
403 | int s; /* index through staffs */ | |
404 | struct LYRFONTSIZE *lfs_p; /* font/size info */ | |
405 | ||
406 | ||
407 | if (Context == C_SCORE) { | |
408 | /* reset all staffs */ | |
409 | Context = C_STAFF; | |
410 | for (s = 1; s <= Score.staffs; s++) { | |
411 | setlyrsize(s, size); | |
412 | } | |
413 | Context = C_SCORE; | |
414 | } | |
415 | else { | |
416 | /* set all place/verse combinations of given staff */ | |
417 | for (lfs_p = Lyrfontsizeinfo_p [staffno]; | |
418 | lfs_p != (struct LYRFONTSIZE *) 0; | |
419 | lfs_p = lfs_p->next) { | |
420 | lfs_p->size = (char) (lfs_p->all == YES | |
421 | ? Score.lyricssize : size); | |
422 | } | |
423 | } | |
424 | } | |
425 | \f | |
426 | ||
427 | /* This function is called when an entire measure has been collected, to | |
428 | * take care of all the lyrics. | |
429 | * For each staff, allocate the proper number of elements for the syls_p | |
430 | * list and fill them in. | |
431 | * Then free all the LYRINFO structs and clean out the Lyr_tbl. | |
432 | */ | |
433 | ||
434 | void | |
435 | attach_lyrics2staffs(mll_staffs_p) | |
436 | ||
437 | struct MAINLL *mll_staffs_p; /* the list of staffs to attch to */ | |
438 | ||
439 | { | |
440 | struct STAFF *staff_p; /* the staff we are currently dealing | |
441 | * with */ | |
442 | int verses; /* how many verses for staff */ | |
443 | struct LYRINFO *lyrinfo_p; /* where lyrics info is stored */ | |
444 | ||
445 | ||
446 | debug(4, "attach_lyrics2staffs"); | |
447 | ||
448 | /* do each staff */ | |
449 | for ( ; mll_staffs_p != (struct MAINLL *) 0; | |
450 | mll_staffs_p = mll_staffs_p->next) { | |
451 | ||
452 | if (mll_staffs_p->str != S_STAFF) { | |
453 | /* must have gotten to end of staffs; done */ | |
454 | break; | |
455 | } | |
456 | ||
457 | /* need staff pointer a lot. Get shorter name for it */ | |
458 | staff_p = mll_staffs_p->u.staff_p; | |
459 | ||
460 | /* count up how many verses there are associated with this | |
461 | * staff */ | |
462 | for ( verses = 0, lyrinfo_p = Lyr_tbl[staff_p->staffno]; | |
463 | lyrinfo_p != (struct LYRINFO *) 0; | |
464 | lyrinfo_p = lyrinfo_p->next) { | |
465 | verses++; | |
466 | } | |
467 | ||
468 | /* if no verses, nothing to do */ | |
469 | if (verses == 0) { | |
470 | continue; | |
471 | } | |
472 | ||
473 | /* alloc space for the appropriate number of verses */ | |
474 | MALLOC(GRPSYL *, staff_p->syls_p, verses); | |
475 | if ((staff_p->sylplace = (short *) malloc | |
476 | (sizeof(short) * verses)) == (short *) 0) { | |
477 | l_no_mem(__FILE__, __LINE__); | |
478 | } | |
479 | staff_p->nsyllists = (short) verses; | |
480 | ||
481 | /* now attach the GRPSYLs and set the places for each */ | |
482 | for (verses = 0, lyrinfo_p = Lyr_tbl[staff_p->staffno]; | |
483 | lyrinfo_p != (struct LYRINFO *) 0; | |
484 | lyrinfo_p = lyrinfo_p->next, verses++) { | |
485 | ||
486 | staff_p->syls_p[verses] = lyrinfo_p->gs_p; | |
487 | staff_p->sylplace[verses] = lyrinfo_p->place; | |
488 | } | |
489 | ||
490 | free_lyrinfo(Lyr_tbl[staff_p->staffno]); | |
491 | Lyr_tbl[staff_p->staffno] = (struct LYRINFO *) 0; | |
492 | } | |
493 | } | |
494 | \f | |
495 | ||
496 | /* recursively free list of LYRINFO structs */ | |
497 | ||
498 | static void | |
499 | free_lyrinfo(lyrinfo_p) | |
500 | ||
501 | struct LYRINFO *lyrinfo_p; /* the list to free */ | |
502 | ||
503 | { | |
504 | if (lyrinfo_p == (struct LYRINFO *) 0) { | |
505 | return; | |
506 | } | |
507 | ||
508 | free_lyrinfo(lyrinfo_p->next); | |
509 | FREE(lyrinfo_p); | |
510 | } | |
511 | \f | |
512 | ||
513 | /* At each bar line, reset previous verse number for auto-verse-numbering */ | |
514 | ||
515 | void | |
516 | lyr_new_bar() | |
517 | { | |
518 | int staff_index; | |
519 | int place_index; | |
520 | ||
521 | for (staff_index = 1; staff_index <= MAXSTAFFS; staff_index++) { | |
522 | for (place_index = 0; place_index < NUM_PLACE; place_index++) { | |
523 | Prev_verse_num[staff_index][place_index] = 0; | |
524 | } | |
525 | } | |
526 | } | |
527 | ||
528 | \f | |
529 | ||
530 | /* in several places we need to copy part of a lyric from one string to | |
531 | * another while keeping track of the font and size changes along the way. | |
532 | * Doing this with a function gets hard to think about because you'd | |
533 | * have to pass around a bunch of pointers to pointers and keep all the | |
534 | * levels of indirection straight, so I opted for a macro. | |
535 | * destbuff is the char array into which to copy. destindex is the subscript | |
536 | * into that array. src_p is a char * from which to copy. delimiter is the | |
537 | * character at which to stop copying. fnt_p and sz_p are pointer to font | |
538 | * and size which need to be updated if the font or size change. | |
539 | */ | |
540 | #define COPY_LYR(destbuff, destindex, src_p, delimiter, fnt_p, sz_p) \ | |
541 | for ( ; *src_p != '\0' && *src_p != delimiter; src_p++) { \ | |
542 | destbuff[destindex++] = *src_p; \ | |
543 | \ | |
544 | switch ( (unsigned) *src_p & 0xff) { \ | |
545 | case STR_FONT: \ | |
546 | *fnt_p = *++src_p; \ | |
547 | destbuff[destindex++] = *src_p; \ | |
548 | break; \ | |
549 | case STR_SIZE: \ | |
550 | *sz_p = *++src_p; \ | |
551 | destbuff[destindex++] = *src_p; \ | |
552 | break; \ | |
553 | case STR_MUS_CHAR: \ | |
554 | destbuff[destindex++] = *++src_p; \ | |
555 | destbuff[destindex++] = *++src_p; \ | |
556 | break; \ | |
557 | case STR_BACKSPACE: \ | |
558 | destbuff[destindex++] = *++src_p; \ | |
559 | break; \ | |
560 | default: \ | |
561 | break; \ | |
562 | } \ | |
563 | } | |
564 | \f | |
565 | ||
566 | ||
567 | /* break a string of lyrics into individual syllables. The following | |
568 | * characters are special: | |
569 | * <space> marks end of syllable | |
570 | * <tab> same as space | |
571 | * - end of syllable | |
572 | * _ end of syllable | |
573 | * '<' beginning of non-lyric item | |
574 | * '>' end of non-lyric item | |
575 | */ | |
576 | /* Each syllable will be returned as a string of the form: | |
577 | * <font> <size> [<STR_PRE> pre-item <STR_PRE_END>] syllable [<STR_PST> post-item <STR_PST_END>] | |
578 | * where | |
579 | * <font> is a 1-byte font identifier, FONT_TR, FONT_TI etc | |
580 | * <size> is a 1-byte size, in points | |
581 | * if there is non-lyrics stuff to be put before the lyric syllable, it | |
582 | * will be surrounded by <STR_PRE> and <STR_PRE_END> characters. | |
583 | * It may contain other commands for font changes, etc. | |
584 | * This field is optional. If present it may be of arbitrary | |
585 | * length, including zero length | |
586 | * If this text is to be used for syllable | |
587 | * placement, the header will be <STR_U_PRE> instead | |
588 | * The syllable follows. It may contain any of the commands found in | |
589 | * any other string. It can be of zero length. | |
590 | * Optionally, there may there something to print after the syllable | |
591 | * that isn't part of the syllable. If there is such a thing, | |
592 | * it will be surrounded by <STR_PST> and <STR_PST_END> characters. | |
593 | * If this text is to be used for syllable placement, the | |
594 | * header will be <STR_U_PST> instead. | |
595 | * Any of the fields can be of zero length, but at least one of them | |
596 | * must be of non-zero length for each syllable to be sensible. | |
597 | * This function should be called after the string has been transformed | |
598 | * to internal format, with font/size changes stored as commands. | |
599 | * If a syllable starts with a positioning value, that is updated. | |
600 | */ | |
601 | ||
602 | static char * | |
603 | next_syl(sylstring_p, font_p, size_p, position_p, staffno) | |
604 | ||
605 | char **sylstring_p; /* address of pointer to current spot in lyric string | |
606 | * of syllables. At entry, its contents should be | |
607 | * the address of the first character of the syllable | |
608 | * to be returned. On return, its contents will be | |
609 | * updated to point to the first character of the | |
610 | * following syllable, to be ready for the next call | |
611 | * to this function. | |
612 | */ | |
613 | int *font_p; /* pointer to current font value, will be updated | |
614 | * with new font if it changes. */ | |
615 | int *size_p; /* pointer to current size value; will be updated | |
616 | * with new size if it changes */ | |
617 | short *position_p; /* pointer to sylposition field, will be updated | |
618 | * with the user-specified position value, if | |
619 | * they specified one, otherwise will be left as is. */ | |
620 | int staffno; /* which staff this syllable is for */ | |
621 | ||
622 | { | |
623 | char *p; /* pointer into lyrics string */ | |
624 | int done; /* boolean to keep track of if we are done */ | |
625 | int font, size; /* original font and size */ | |
626 | int i; /* index into sylbuff */ | |
627 | char sylbuff[BUFSIZ]; /* temporary storage for a syllable */ | |
628 | ||
629 | ||
630 | /* initialize */ | |
631 | sylbuff[0] = '\0'; | |
632 | i = 0; | |
633 | font = *font_p; | |
634 | size = *size_p; | |
635 | ||
636 | /* skip any leading white space */ | |
637 | for (p = *sylstring_p; *p != '\0'; p++) { | |
638 | if (*p != ' ') { | |
639 | break; | |
640 | } | |
641 | } | |
642 | ||
643 | /* see if we have a non-lyrics before the lyric */ | |
644 | if ( *p == '<') { | |
645 | ||
646 | /* we do have a non-lyric. Put in the header, and copy up | |
647 | * to the '>', keeping track of any font/size changes | |
648 | * along the way */ | |
649 | if (*(p+1) == '^') { | |
650 | sylbuff[i++] = (char) STR_U_PRE; | |
651 | p++; | |
652 | } | |
653 | else { | |
654 | sylbuff[i++] = (char) STR_PRE; | |
655 | } | |
656 | p++; | |
657 | COPY_LYR(sylbuff, i, p, '>', font_p, size_p); | |
658 | ||
659 | /* add in the > marker */ | |
660 | sylbuff[i++] = (char) STR_PRE_END; | |
661 | if (*p == '\0') { | |
662 | yyerror("missing '>' in lyric"); | |
663 | } | |
664 | else { | |
665 | p++; | |
666 | } | |
667 | } | |
668 | ||
669 | /* see if user gave a position value */ | |
670 | if (*p == '|') { | |
671 | /* use default value from parameter */ | |
672 | *position_p = svpath(staffno, SYLPOSITION)->sylposition; | |
673 | p++; | |
674 | } | |
675 | else if ( isdigit(*p) || | |
676 | ( (*p == '-' || *p == '+') && isdigit(*(p+1)) ) ) { | |
677 | char *after_num_p; | |
678 | int value; | |
679 | ||
680 | /* if there is a pipe after the number, it's a position */ | |
681 | value = strtol(p, &after_num_p, 10); | |
682 | if ( *after_num_p == '|') { | |
683 | *position_p = value; | |
684 | p = after_num_p + 1; | |
685 | } | |
686 | } | |
687 | ||
688 | /* now collect the lyric syllable itself */ | |
689 | for ( done = NO; *p != '\0' && i < BUFSIZ; p++) { | |
690 | ||
691 | switch ( (unsigned) *p & 0xff) { | |
692 | ||
693 | case ' ': | |
694 | case '\t': | |
695 | /* definitely end of this lyric syllable */ | |
696 | done = YES; | |
697 | break; | |
698 | ||
699 | ||
700 | case '~': | |
701 | /* two syllables joined into one. Replace the ~ | |
702 | * by a space */ | |
703 | sylbuff[i++] = ' '; | |
704 | p++; | |
705 | break; | |
706 | ||
707 | case '-': | |
708 | case '_': | |
709 | /* end of syllable */ | |
710 | /* need to peek ahead to check for non-lyric following */ | |
711 | sylbuff[i++] = *p++; | |
712 | if ( *p != '<') { | |
713 | done = YES; | |
714 | break; | |
715 | } | |
716 | /*FALLTHRU*/ | |
717 | ||
718 | case '<': | |
719 | if (*(p+1) == '^') { | |
720 | sylbuff[i++] = (char) STR_U_PST; | |
721 | p++; | |
722 | } | |
723 | else { | |
724 | sylbuff[i++] = (char) STR_PST; | |
725 | } | |
726 | p++; | |
727 | COPY_LYR(sylbuff, i, p, '>', font_p, size_p); | |
728 | ||
729 | sylbuff[i++] = (char) STR_PST_END; | |
730 | p++; | |
731 | /* A ~ joins this syllable with the next to make | |
732 | * them effectively one, but anything else ends | |
733 | * the syllable. But copy - or _ if they are there */ | |
734 | if ( *p != '~') { | |
735 | if (*p == '-' || *p == '_') { | |
736 | sylbuff[i++] = *p++; | |
737 | } | |
738 | done = YES; | |
739 | } | |
740 | break; | |
741 | ||
742 | case STR_FONT: | |
743 | sylbuff[i++] = *p++; | |
744 | *font_p = *p; | |
745 | #ifdef EXTCHAR | |
746 | if (*font_p >= FONT_XTR) { | |
747 | sylbuff[i++] = *p++; | |
748 | } | |
749 | #endif | |
750 | break; | |
751 | ||
752 | case STR_SIZE: | |
753 | sylbuff[i++] = *p++; | |
754 | *size_p = *p; | |
755 | break; | |
756 | ||
757 | case STR_BACKSPACE: | |
758 | sylbuff[i++] = *p++; | |
759 | break; | |
760 | ||
761 | case STR_MUS_CHAR: | |
762 | sylbuff[i++] = *p++; | |
763 | sylbuff[i++] = *p++; | |
764 | break; | |
765 | ||
766 | case STR_BOX: | |
767 | yyerror("boxed text not allowed in lyrics"); | |
768 | break; | |
769 | ||
770 | case STR_BOX_END: | |
771 | break; | |
772 | ||
773 | case STR_CIR: | |
774 | yyerror("circled text not allowed in lyrics"); | |
775 | break; | |
776 | ||
777 | case STR_CIR_END: | |
778 | break; | |
779 | ||
780 | case STR_PILE: | |
781 | yyerror("\\: not allowed in lyric syllable"); | |
782 | break; | |
783 | ||
784 | case STR_C_ALIGN: | |
785 | case STR_L_ALIGN: | |
786 | yyerror("alignment not allowed in lyric syllable"); | |
787 | break; | |
788 | ||
789 | default: | |
790 | break; | |
791 | } | |
792 | ||
793 | if (done == NO) { | |
794 | sylbuff[i++] = *p; | |
795 | } | |
796 | else { | |
797 | break; | |
798 | } | |
799 | } | |
800 | ||
801 | sylbuff[i] = '\0'; | |
802 | ||
803 | if (i == 0) { | |
804 | yyerror("too few syllables in string"); | |
805 | } | |
806 | ||
807 | /* prepare for next call to this function */ | |
808 | *sylstring_p = p; | |
809 | ||
810 | /* return a copy of the extracted syllable */ | |
811 | return(copy_string(sylbuff, font, size)); | |
812 | } | |
813 | \f | |
814 | ||
815 | /* given a syllable string, return the width (in inches) of the non-lyric | |
816 | * parts and of the actual syllable */ | |
817 | ||
818 | void | |
819 | sylwidth(lyrstring, wid_b4_syl_p, wid_real_syl_p, wid_after_syl_p) | |
820 | ||
821 | char *lyrstring; | |
822 | float *wid_b4_syl_p; /* width of leading non-lyrics will be put here */ | |
823 | float *wid_real_syl_p; /* width of actual syllable will be put here */ | |
824 | float *wid_after_syl_p; /* width of trailing non-lyric will be put here */ | |
825 | ||
826 | { | |
827 | do_sylwidth(lyrstring, wid_b4_syl_p, wid_real_syl_p, wid_after_syl_p, | |
828 | NO); | |
829 | } | |
830 | \f | |
831 | ||
832 | /* find width of syllable and <...> things. When called in placement phase | |
833 | * we count the <^...> and don't count <...>. When called in print phase | |
834 | * we do the opposite to compensate. | |
835 | */ | |
836 | ||
837 | static void | |
838 | do_sylwidth(lyrstring, wid_b4_syl_p, wid_real_syl_p, wid_after_syl_p, | |
839 | compensating) | |
840 | ||
841 | char *lyrstring; | |
842 | float *wid_b4_syl_p; /* width of leading non-lyrics will be put here */ | |
843 | float *wid_real_syl_p; /* width of actual syllable will be put here */ | |
844 | float *wid_after_syl_p; /* width of trailing non-lyric will be put here */ | |
845 | int compensating; /* YES if being called from print phrase when we | |
846 | * have to compensate for the fact that <...> may | |
847 | * not have been used in placement. */ | |
848 | ||
849 | { | |
850 | int pre_counts = NO; /* if pre width should be included */ | |
851 | int post_counts = NO; /* if post width should be included */ | |
852 | int had_post = NO; /* if had post <...> */ | |
853 | float w1 = 0.0; /* width of pre */ | |
854 | float w2 = 0.0; /* width of pre + syllable */ | |
855 | float w3; /* width of entire string */ | |
856 | char *p; | |
857 | char save; /* temp storage */ | |
858 | ||
859 | ||
860 | if (lyrstring == (char *) 0) { | |
861 | *wid_b4_syl_p = *wid_real_syl_p = *wid_after_syl_p = 0.0; | |
862 | return; | |
863 | } | |
864 | ||
865 | for (p = lyrstring; *p != '\0'; p++) { | |
866 | switch ( (unsigned) *p & 0xff) { | |
867 | case STR_PRE: | |
868 | if (compensating == YES) { | |
869 | pre_counts = YES; | |
870 | } | |
871 | break; | |
872 | case STR_U_PRE: | |
873 | if (compensating == NO) { | |
874 | pre_counts = YES; | |
875 | } | |
876 | break; | |
877 | case STR_PRE_END: | |
878 | /* get width of string so far. Temporarily shorten | |
879 | * string to this point and get its length. This | |
880 | * will be the length of the preceeding <...> */ | |
881 | *p = '\0'; | |
882 | w1 = strwidth(lyrstring); | |
883 | *p = (char) STR_PRE_END; | |
884 | break; | |
885 | case STR_U_PST: | |
886 | /* get width of string so far. Temporarily shorten | |
887 | * string to this point and get its length. This | |
888 | * will be the length of the syllable and its | |
889 | * preceeding <...> */ | |
890 | if (compensating == NO) { | |
891 | post_counts = YES; | |
892 | } | |
893 | save = *p; | |
894 | *p = '\0'; | |
895 | w2 = strwidth(lyrstring); | |
896 | *p = save; | |
897 | had_post = YES; | |
898 | break; | |
899 | case STR_PST: | |
900 | if (compensating == YES) { | |
901 | post_counts = YES; | |
902 | } | |
903 | save = *p; | |
904 | *p = '\0'; | |
905 | w2 = strwidth(lyrstring); | |
906 | *p = save; | |
907 | had_post = YES; | |
908 | break; | |
909 | default: | |
910 | break; | |
911 | } | |
912 | } | |
913 | ||
914 | /* get length of entire string */ | |
915 | w3 = strwidth(lyrstring); | |
916 | ||
917 | /* if there wasn't a post <...> we didn't yet get the width of | |
918 | * the syllable plus preceeding <...> */ | |
919 | if (had_post == NO) { | |
920 | w2 = w3; | |
921 | } | |
922 | ||
923 | /* now calculate and return the widths */ | |
924 | *wid_b4_syl_p = (pre_counts == YES ? w1 : 0.0); | |
925 | *wid_real_syl_p = w2 - w1; | |
926 | *wid_after_syl_p = (post_counts == YES ? w3 - w2 : 0.0); | |
927 | } | |
928 | \f | |
929 | ||
930 | /* during placement phase, <...> things were used or not used as appropriate | |
931 | * for setting placement. During print phrase, we do the opposite to | |
932 | * compensate, and update the group east and west boundaries as necessary */ | |
933 | void | |
934 | lyr_compensate(gs_p) | |
935 | ||
936 | struct GRPSYL *gs_p; | |
937 | ||
938 | { | |
939 | float pre_wid, syl_wid, post_wid; | |
940 | ||
941 | do_sylwidth(gs_p->syl, &pre_wid, &syl_wid, &post_wid, YES); | |
942 | gs_p->c[AW] -= pre_wid; | |
943 | gs_p->c[AE] += post_wid; | |
944 | } | |
945 | \f | |
946 | ||
947 | /* every time a verse number is used, see whether we've already had that | |
948 | * verse number before. if not, add it to the list of verse numbers used. */ | |
949 | /* We could keep each range of defined verses in a RANGELIST, so that, | |
950 | * for example, 1-3 could be keep in a single struct. However, trying to | |
951 | * coalese the list could get very hairy, so do the simple-minded way of | |
952 | * saving each unique verse number in its own struct. We could also | |
953 | * insertion sort the list, but rarely will there be more than a couple | |
954 | * verses, and inserting into a singly linked list takes a slight amount | |
955 | * of work, so be very lazy and just search the whole list each time and | |
956 | * insert at beginning if need to add to list. */ | |
957 | ||
958 | static void | |
959 | vno_used(vno) | |
960 | ||
961 | int vno; /* the verse number to check */ | |
962 | ||
963 | { | |
964 | struct RANGELIST *v_p; /* to walk through list of verse nums used */ | |
965 | struct RANGELIST **list_p_p; /* which list to check */ | |
966 | ||
967 | ||
968 | switch (Place) { | |
969 | case PL_ABOVE: | |
970 | list_p_p = &Above_vnumbers_used; | |
971 | break; | |
972 | case PL_BETWEEN: | |
973 | list_p_p = &Between_vnumbers_used; | |
974 | break; | |
975 | case PL_BELOW: | |
976 | case PL_UNKNOWN: | |
977 | list_p_p = &Below_vnumbers_used; | |
978 | break; | |
979 | default: | |
980 | pfatal("illegal place in vno_used"); | |
981 | /*NOTREACHED*/ | |
982 | return; | |
983 | } | |
984 | ||
985 | /* see if this verse is already on the list */ | |
986 | for (v_p = *list_p_p; v_p != (struct RANGELIST *) 0; v_p = v_p->next) { | |
987 | if (v_p->begin == vno) { | |
988 | /* already had this verse before */ | |
989 | return; | |
990 | } | |
991 | } | |
992 | ||
993 | /* must not have seen this verse number before, so add it */ | |
994 | CALLOC(RANGELIST, v_p, 1); | |
995 | v_p->begin = (short) vno; | |
996 | /* ->end is not used in this list */ | |
997 | v_p->next = *list_p_p; | |
998 | *list_p_p = v_p; | |
999 | } | |
1000 | \f | |
1001 | ||
1002 | /* when parsing is complete, we can find out how many unique verse numbers | |
1003 | * there were in the input */ | |
1004 | ||
1005 | void | |
1006 | set_maxverses() | |
1007 | { | |
1008 | debug(4, "set_maxverses"); | |
1009 | ||
1010 | count_verses(Above_vnumbers_used); | |
1011 | count_verses(Below_vnumbers_used); | |
1012 | count_verses(Between_vnumbers_used); | |
1013 | } | |
1014 | ||
1015 | /* recursively walk down list of verse numbers used. Count them up and | |
1016 | * free them while unwinding */ | |
1017 | ||
1018 | static void | |
1019 | count_verses(used_p) | |
1020 | ||
1021 | struct RANGELIST *used_p; | |
1022 | ||
1023 | { | |
1024 | if (used_p == (struct RANGELIST *) 0) { | |
1025 | return; | |
1026 | } | |
1027 | ||
1028 | count_verses(used_p->next); | |
1029 | Maxverses++; | |
1030 | FREE(used_p); | |
1031 | } | |
1032 | \f | |
1033 | ||
1034 | /* Return pointer to the SSV that contains the default timeunit information | |
1035 | * for verses being defined. Make sure if there are multiple staffs | |
1036 | * being defined, they all have the same default timeunit. If there is only | |
1037 | * one voice on the staff, use that for default. If there are 2 voices, if the | |
1038 | * place is PL_ABOVE use voice 1, otherwise use voice 2. */ | |
1039 | ||
1040 | struct SSV * | |
1041 | get_lyr_dflt_timeunit_ssv() | |
1042 | ||
1043 | { | |
1044 | struct RANGELIST *staffrange_p; /* to index through list of staffs */ | |
1045 | struct SSV *ssv_p; /* containing relevent timeunit */ | |
1046 | struct SSV *ref_ssv_p; /* to ensure consistency */ | |
1047 | RATIONAL timeunit; /* timeunit for current staff */ | |
1048 | RATIONAL reference_timeunit; /* the timeunit found on previous | |
1049 | * staff, for comparison to make sure | |
1050 | * they are the same */ | |
1051 | int staff; | |
1052 | ||
1053 | ||
1054 | reference_timeunit = Zero; | |
1055 | /* if all else fails, use Score value */ | |
1056 | ssv_p = ref_ssv_p = &Score; | |
1057 | ||
1058 | /* go down the list of staffs, get timeunit for each */ | |
1059 | for (staffrange_p = Staffrange_p; | |
1060 | staffrange_p != (struct RANGELIST *) 0; | |
1061 | staffrange_p = staffrange_p->next) { | |
1062 | ||
1063 | for (staff = staffrange_p->begin; staff <= staffrange_p->end; | |
1064 | staff++) { | |
1065 | ||
1066 | /* get appropriate default timeunit value */ | |
1067 | if (svpath(staff, VSCHEME)->vscheme == V_1 || | |
1068 | Place == PL_ABOVE) { | |
1069 | ssv_p = vvpath(staff, 1, TIMEUNIT); | |
1070 | } | |
1071 | else { | |
1072 | ssv_p = vvpath(staff, 2, TIMEUNIT); | |
1073 | } | |
1074 | timeunit = ssv_p->timeunit; | |
1075 | ||
1076 | /* check for consistency */ | |
1077 | if ( NE(reference_timeunit, Zero) ) { | |
1078 | if ( NE(timeunit, reference_timeunit) || | |
1079 | timelists_equal( | |
1080 | ssv_p->timelist_p, | |
1081 | ref_ssv_p->timelist_p) == NO) { | |
1082 | /* have a mis-match. Give error message, | |
1083 | * and return the first timeunit we got. | |
1084 | * No reason to check any more, because | |
1085 | * all that may happen is that we'll | |
1086 | * print lots more error messages for | |
1087 | * the same problem. */ | |
1088 | yyerror("timeunit value must be the same for all lyric staffs being defined on the same input line"); | |
1089 | return(ssv_p); | |
1090 | } | |
1091 | } | |
1092 | else { | |
1093 | /* first time through. Now we have a timeunit | |
1094 | * to use for default */ | |
1095 | reference_timeunit = timeunit; | |
1096 | ref_ssv_p = ssv_p; | |
1097 | } | |
1098 | } | |
1099 | } | |
1100 | ||
1101 | /* Used to pfatal if couldn't find default value. However, that can | |
1102 | * happen if user specifies an invalid staff number, so that isn't | |
1103 | * a program bug, but a user error. The user error would already have | |
1104 | * been flagged, so no reason to complain at all here */ | |
1105 | ||
1106 | return(ssv_p); | |
1107 | } | |
1108 | \f | |
1109 | ||
1110 | /* user wants us to derive the lyrics time values from corresponding music | |
1111 | * time values. Find the proper list of GRPSYLs to copy time values from, | |
1112 | * and make a copy of that list, with field set properly for lyrics. */ | |
1113 | ||
1114 | struct GRPSYL * | |
1115 | derive_lyrtime() | |
1116 | ||
1117 | { | |
1118 | struct MAINLL *mll_p; /* to find STAFF to derive from */ | |
1119 | struct GRPSYL *new_list_p; /* the list of derived time values */ | |
1120 | struct GRPSYL *gs_p; /* to walk through new_list_p */ | |
1121 | struct GRPSYL *ref_gs_p; /* to walk through the reference list-- | |
1122 | * the list we are deriving from */ | |
1123 | int staff, voice; /* which list of GRPSYLs to clone */ | |
1124 | ||
1125 | ||
1126 | /* If there are no staffs associated with these lyrics, then nothing | |
1127 | * to do here. We should have already printed an error elsewhere */ | |
1128 | if (Staffrange_p == (struct RANGELIST *) 0) { | |
1129 | return (struct GRPSYL *) 0; | |
1130 | } | |
1131 | ||
1132 | /* find the proper music GRPSYL from which to derive time values */ | |
1133 | staff = leadstaff(); | |
1134 | for (mll_p = Mainlltc_p; mll_p != (struct MAINLL *) 0; | |
1135 | mll_p = mll_p->prev) { | |
1136 | ||
1137 | /* if back up all the way to a bar, user hasn't defined the | |
1138 | * right staff's music input yet */ | |
1139 | if (mll_p->str == S_BAR) { | |
1140 | /* pretend we fell off top of list and break out. | |
1141 | * That way we only need one copy of error message code */ | |
1142 | mll_p = (struct MAINLL *) 0; | |
1143 | break; | |
1144 | } | |
1145 | if (mll_p->str == S_STAFF && mll_p->u.staff_p->staffno == staff) { | |
1146 | /* found the right staff data */ | |
1147 | break; | |
1148 | } | |
1149 | } | |
1150 | ||
1151 | if (mll_p == (struct MAINLL *) 0) { | |
1152 | l_yyerror(Curr_filename, yylineno, | |
1153 | "can't derive lyrics time values: staff %d music not defined yet", staff); | |
1154 | return (struct GRPSYL *) 0; | |
1155 | } | |
1156 | ||
1157 | /* usually use voice 1 of first staff specified. Only exceptions | |
1158 | * are if voice 1 is invisible or nonexistent or if explicitly below, | |
1159 | * and there is a visible voice 2, in which case voice 2 is used */ | |
1160 | voice = 0; | |
1161 | if ((vvpath(staff, 1, VISIBLE)->visible == NO || | |
1162 | mll_p->u.staff_p->groups_p[0] == (struct GRPSYL *) 0 | |
1163 | || Place == PL_BELOW) | |
1164 | && mll_p->u.staff_p->groups_p[1] != (struct GRPSYL *) 0 | |
1165 | && vvpath(staff, 2, VISIBLE)->visible == YES) { | |
1166 | voice = 1; | |
1167 | } | |
1168 | /* One more exception. If both voices are invisible, but we would | |
1169 | * have used voice 2 if it was visible, use voice 2. Otherwise | |
1170 | * if times would normally be derived from voice 2, but the | |
1171 | * whole staff is invisible, we could derive the wrong values. */ | |
1172 | if (vvpath(staff, 1, VISIBLE)->visible == NO && | |
1173 | vvpath(staff, 2, VISIBLE)->visible == NO && | |
1174 | mll_p->u.staff_p->groups_p[1] != (struct GRPSYL *) 0 && | |
1175 | Place == PL_BELOW) { | |
1176 | voice = 1; | |
1177 | } | |
1178 | ||
1179 | if (mll_p->u.staff_p->groups_p[voice] == (struct GRPSYL *) 0) { | |
1180 | l_yyerror(Curr_filename, yylineno, | |
1181 | "can't derive lyrics time values: staff %d voice %d music not defined yet", staff, voice + 1); | |
1182 | return (struct GRPSYL *) 0; | |
1183 | } | |
1184 | ||
1185 | new_list_p = clone_gs_list(mll_p->u.staff_p->groups_p[voice], NO); | |
1186 | ||
1187 | /* grace notes don't count in the time derivation, so remove | |
1188 | * them from the cloned list */ | |
1189 | for (gs_p = new_list_p; gs_p != (struct GRPSYL *) 0; gs_p = gs_p->next) { | |
1190 | if (gs_p->grpvalue == GV_ZERO) { | |
1191 | struct GRPSYL *to_free_p; | |
1192 | to_free_p = gs_p; | |
1193 | if (gs_p->prev == 0) { | |
1194 | new_list_p = gs_p->next; | |
1195 | } | |
1196 | else { | |
1197 | gs_p->prev->next = gs_p->next; | |
1198 | } | |
1199 | /* Note that there should always be a 'next' after | |
1200 | * a grace note, so this 'if' shouldn't really be | |
1201 | * necessary, but it is here as defensive code. */ | |
1202 | if (gs_p->next != 0) { | |
1203 | gs_p->next->prev = gs_p->prev; | |
1204 | } | |
1205 | FREE(to_free_p); | |
1206 | } | |
1207 | } | |
1208 | ||
1209 | /* go through cloned list, changing type to lyrics and changing rests | |
1210 | * in the music to spaces for the lyrics. Also deal with ties and slurs, | |
1211 | * since notes that are tied or slurred to will be treated like a | |
1212 | * space, since there is probably only a single syllable wanted. */ | |
1213 | for (gs_p = new_list_p, ref_gs_p = mll_p->u.staff_p->groups_p[voice]; | |
1214 | gs_p != (struct GRPSYL *) 0; | |
1215 | gs_p = gs_p->next, ref_gs_p = ref_gs_p->next) { | |
1216 | /* Skip graces in reference list. (There aren't any in | |
1217 | * the new list since we removed them above.) */ | |
1218 | while (ref_gs_p->grpvalue == GV_ZERO) { | |
1219 | ref_gs_p = ref_gs_p->next; | |
1220 | if (ref_gs_p == 0) { | |
1221 | /* should be impossible to get here */ | |
1222 | pfatal("unexpected null ref_gs_p in derive_lyrtime"); | |
1223 | } | |
1224 | } | |
1225 | ||
1226 | gs_p->grpsyl = GS_SYLLABLE; | |
1227 | if (ref_gs_p->grpcont == GC_REST) { | |
1228 | gs_p->grpcont = GC_SPACE; | |
1229 | } | |
1230 | else if (ref_gs_p->grpcont == GC_NOTES && ref_gs_p->nnotes > 0) { | |
1231 | /* if the top note of the chord is tied or slurred, | |
1232 | * or the entire chord is tied, | |
1233 | * make the following lyrics GRPSYL, if any, a space. */ | |
1234 | if ((ref_gs_p->notelist[0].tie == YES || | |
1235 | ref_gs_p->tie == YES || | |
1236 | ref_gs_p->notelist[0].nslurto > 0) && | |
1237 | gs_p->next != (struct GRPSYL *) 0) { | |
1238 | gs_p->next->grpcont = GC_SPACE; | |
1239 | } | |
1240 | } | |
1241 | } | |
1242 | ||
1243 | /* One more detail: if the first note was tied-to or slurred-to from | |
1244 | * the previous measure, we have to change that to a space. To do that, | |
1245 | * we call prevgrpsyl, but it expects the staffno and vno to be filled | |
1246 | * in on the GRPSYL passed to it, and we're so early in parsing that | |
1247 | * that hasn't happened yet. So first have to patch that up. Later on, | |
1248 | * all the GRPSYLs will get the staffno and vno filled in, but it won't | |
1249 | * hurt anything that we've already done this one here; they will | |
1250 | * just be overwritten with the same values. */ | |
1251 | ref_gs_p = mll_p->u.staff_p->groups_p[voice]; | |
1252 | ref_gs_p->staffno = mll_p->u.staff_p->staffno; | |
1253 | ref_gs_p->vno = voice + 1; | |
1254 | if ((gs_p = prevgrpsyl(ref_gs_p, &mll_p)) != (struct GRPSYL *) 0) { | |
1255 | if (gs_p->grpcont == GC_NOTES && gs_p->nnotes > 0) { | |
1256 | if (gs_p->notelist[0].tie == YES || | |
1257 | gs_p->tie == YES || | |
1258 | gs_p->notelist[0].nslurto > 0) { | |
1259 | new_list_p->grpcont = GC_SPACE; | |
1260 | } | |
1261 | } | |
1262 | } | |
1263 | ||
1264 | return (new_list_p); | |
1265 | } | |
1266 |