2 /* Copyright (c) 1995, 1997, 1998, 1999, 2000, 2001, 2002, 2004, 2005, 2006 by Arkkra Enterprises */
3 /* All rights reserved */
5 /* functions called by the parse phase to deal with lyrics */
12 /* information about a measure-worth of lyrics */
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
21 /* current font/size for each staff/verse/place combination */
25 char place
; /* PL_ABOVE, etc */
28 char all
; /* YES if "above all" or "below all".
29 * In that case, the staffno is
31 struct LYRFONTSIZE
*next
; /* linked list */
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];
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];
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
;
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
];
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
,
57 static void updlyrfontsize
P((struct LYRFONTSIZE
*lyrfontsize_p
,
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
,
64 static void count_verses
P((struct RANGELIST
*used_p
));
65 static void vno_used
P((int vno
));
68 /* given a range of verses, save the range for later use */
73 int begin
; /* first verse in range */
74 int end
; /* last verse number in range */
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.
85 if (begin
< 1 && begin
!= -1) {
86 yyerror("verse number must be >= 1");
91 yyerror("end of verse range smaller than beginning");
95 save_vno_range(begin
, end
);
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.
107 proc_lyrics(grpsyl_p
, lyrstring
)
109 struct GRPSYL
*grpsyl_p
; /* list of GRPSYLs with time values */
110 char *lyrstring
; /* string containing the lyrics */
113 struct RANGELIST
*slist_p
; /* walk through list of staffs */
114 struct RANGELIST
*vlist_p
; /* walk through list of verses */
120 if (grpsyl_p
== (struct GRPSYL
*) 0 || lyrstring
== (char *) 0) {
124 debug(2, "proc_lyrics file=%s lineno=%d", grpsyl_p
->inputfile
,
125 grpsyl_p
->inputlineno
);
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
;
136 /* do each appropriate verse */
137 for (vlist_p
= Vnorange_p
;
138 vlist_p
!= (struct RANGELIST
*) 0;
139 vlist_p
= vlist_p
->next
) {
141 for (verse
= vlist_p
->begin
;
142 verse
<= vlist_p
->end
;
145 /* -1 means one more than previous */
148 verse
= Prev_verse_num
[staffno
][place
] + 1;
150 Prev_verse_num
[staffno
][place
] = verse
;
151 /* connect to proper staff */
152 assoc_lyr2staff(staffno
, verse
,
154 slist_p
->all
, place
);
156 /* mark that we've use this verse # */
163 /* free the vno rangelist. Don't free the staff info yet, because
164 * there may be more verses */
167 /* the lyrics string has been broken into syllables. Don't need
168 * the original string anymore */
173 /* connect a list of syllable to specified STAFF */
176 assoc_lyr2staff(staffno
, verse
, gs_p
, lyrstring
, all
, place
)
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_* */
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
193 char *lyr_copy
; /* copy of lyrics */
196 struct LYRFONTSIZE
*lyrfontsize_p
; /* info about font/size for
197 * current staff/verse/place */
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
,
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",
211 /* make a copy of the grpsyl list for this staff/verse */
212 gs_p
= clone_gs_list(gs_p
, NO
);
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
;
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
) ) {
225 lyrinfo_p
= (*insert_place_p_p
);
227 if ( lyrinfo_p
->vno
> verse
) {
228 /* need to insert new one right before this one */
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",
240 new_p
->next
= *insert_place_p_p
;
241 *insert_place_p_p
= new_p
;
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
;
250 lyr_copy
= lyrstring
= copy_string(lyrstring
+ 2, font
, size
);
252 /* get into internal format */
253 fix_string(lyrstring
, font
, size
, Curr_filename
, yylineno
);
255 /* skip past the font/size */
258 /* fill in vno, staffno, and syllables */
259 for ( ; gs_p
!= (struct GRPSYL
*) 0; gs_p
= gs_p
->next
) {
261 gs_p
->staffno
= (short) staffno
;
262 gs_p
->vno
= (short) verse
;
264 /* if this GRPSYL is a space, don't fill in a syllable */
265 if (gs_p
->grpcont
== GC_SPACE
) {
269 /* otherwise, find the next syllable, and store it in
271 gs_p
->syl
= next_syl(&lyrstring
, &font
, &size
,
272 &(gs_p
->sylposition
), staffno
);
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
);
279 /* skip over any trailing white space */
280 while (*lyrstring
== ' ' || *lyrstring
== '\t') {
284 if (*lyrstring
!= '\0') {
285 yyerror("too many syllables in string");
288 /* the copy has been broken into syllables. Free the copy */
293 /* given a staffno, verse, and place, return (via pointer to struct of info)
294 * the font and size that should be used */
296 static struct LYRFONTSIZE
*
297 getlyrfontsize(staffno
, verse
, place
, all
)
302 int all
; /* YES if associated with "all" */
305 struct LYRFONTSIZE
*lfs_p
; /* walk through linked list */
308 /* if this staff/verse/place is on the list, use the values stored
310 for (lfs_p
= Lyrfontsizeinfo_p
[staffno
];
311 lfs_p
!= (struct LYRFONTSIZE
*) 0;
312 lfs_p
= lfs_p
->next
) {
314 if (lfs_p
->staffno
== staffno
&& lfs_p
->verse
== verse
315 && lfs_p
->place
== place
&& lfs_p
->all
== all
) {
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
;
327 lfs_p
->font
= (char) (Score
.lyricsfamily
+ Score
.lyricsfont
);
328 lfs_p
->size
= (char) Score
.lyricssize
;
331 lfs_p
->font
= svpath(staffno
, LYRICSFAMILY
)->lyricsfamily
332 + svpath(staffno
, LYRICSFONT
)->lyricsfont
;
333 lfs_p
->size
= svpath(staffno
, LYRICSFONT
)->lyricssize
;
335 lfs_p
->next
= Lyrfontsizeinfo_p
[ staffno
];
336 Lyrfontsizeinfo_p
[ staffno
] = lfs_p
;
342 /* update values of font/size for a given LYRFONTSIZE struct */
345 updlyrfontsize(lyrfontsize_p
, font
, size
)
347 struct LYRFONTSIZE
*lyrfontsize_p
;
352 lyrfontsize_p
->font
= (char) font
;
353 lyrfontsize_p
->size
= (char) size
;
357 /* when user sets lyricsfont via an SSV, that overrides whatever fonts are
358 * currently in effect, so change them. */
361 setlyrfont(staffno
, font
)
367 int s
; /* index through staffs */
368 struct LYRFONTSIZE
*lfs_p
; /* info about font/size */
371 if (Context
== C_SCORE
) {
373 /* reset all staffs */
374 for (s
= 1; s
<= Score
.staffs
; s
++) {
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
386 : svpath(staffno
, LYRICSFAMILY
)->lyricsfamily
393 /* when user sets lyricsize via an SSV, that overrides whatever fonts are
394 * currently in effect, so change them. */
397 setlyrsize(staffno
, size
)
403 int s
; /* index through staffs */
404 struct LYRFONTSIZE
*lfs_p
; /* font/size info */
407 if (Context
== C_SCORE
) {
408 /* reset all staffs */
410 for (s
= 1; s
<= Score
.staffs
; s
++) {
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
);
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.
435 attach_lyrics2staffs(mll_staffs_p
)
437 struct MAINLL
*mll_staffs_p
; /* the list of staffs to attch to */
440 struct STAFF
*staff_p
; /* the staff we are currently dealing
442 int verses
; /* how many verses for staff */
443 struct LYRINFO
*lyrinfo_p
; /* where lyrics info is stored */
446 debug(4, "attach_lyrics2staffs");
449 for ( ; mll_staffs_p
!= (struct MAINLL
*) 0;
450 mll_staffs_p
= mll_staffs_p
->next
) {
452 if (mll_staffs_p
->str
!= S_STAFF
) {
453 /* must have gotten to end of staffs; done */
457 /* need staff pointer a lot. Get shorter name for it */
458 staff_p
= mll_staffs_p
->u
.staff_p
;
460 /* count up how many verses there are associated with this
462 for ( verses
= 0, lyrinfo_p
= Lyr_tbl
[staff_p
->staffno
];
463 lyrinfo_p
!= (struct LYRINFO
*) 0;
464 lyrinfo_p
= lyrinfo_p
->next
) {
468 /* if no verses, nothing to do */
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__
);
479 staff_p
->nsyllists
= (short) verses
;
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
++) {
486 staff_p
->syls_p
[verses
] = lyrinfo_p
->gs_p
;
487 staff_p
->sylplace
[verses
] = lyrinfo_p
->place
;
490 free_lyrinfo(Lyr_tbl
[staff_p
->staffno
]);
491 Lyr_tbl
[staff_p
->staffno
] = (struct LYRINFO
*) 0;
496 /* recursively free list of LYRINFO structs */
499 free_lyrinfo(lyrinfo_p
)
501 struct LYRINFO
*lyrinfo_p
; /* the list to free */
504 if (lyrinfo_p
== (struct LYRINFO
*) 0) {
508 free_lyrinfo(lyrinfo_p
->next
);
513 /* At each bar line, reset previous verse number for auto-verse-numbering */
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;
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.
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; \
544 switch ( (unsigned) *src_p & 0xff) { \
547 destbuff[destindex++] = *src_p; \
551 destbuff[destindex++] = *src_p; \
554 destbuff[destindex++] = *++src_p; \
555 destbuff[destindex++] = *++src_p; \
557 case STR_BACKSPACE: \
558 destbuff[destindex++] = *++src_p; \
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
573 * '<' beginning of non-lyric item
574 * '>' end of non-lyric item
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>]
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.
603 next_syl(sylstring_p
, font_p
, size_p
, position_p
, staffno
)
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
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 */
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 */
636 /* skip any leading white space */
637 for (p
= *sylstring_p
; *p
!= '\0'; p
++) {
643 /* see if we have a non-lyrics before the lyric */
646 /* we do have a non-lyric. Put in the header, and copy up
647 * to the '>', keeping track of any font/size changes
650 sylbuff
[i
++] = (char) STR_U_PRE
;
654 sylbuff
[i
++] = (char) STR_PRE
;
657 COPY_LYR(sylbuff
, i
, p
, '>', font_p
, size_p
);
659 /* add in the > marker */
660 sylbuff
[i
++] = (char) STR_PRE_END
;
662 yyerror("missing '>' in lyric");
669 /* see if user gave a position value */
671 /* use default value from parameter */
672 *position_p
= svpath(staffno
, SYLPOSITION
)->sylposition
;
675 else if ( isdigit(*p
) ||
676 ( (*p
== '-' || *p
== '+') && isdigit(*(p
+1)) ) ) {
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
== '|') {
688 /* now collect the lyric syllable itself */
689 for ( done
= NO
; *p
!= '\0' && i
< BUFSIZ
; p
++) {
691 switch ( (unsigned) *p
& 0xff) {
695 /* definitely end of this lyric syllable */
701 /* two syllables joined into one. Replace the ~
709 /* end of syllable */
710 /* need to peek ahead to check for non-lyric following */
720 sylbuff
[i
++] = (char) STR_U_PST
;
724 sylbuff
[i
++] = (char) STR_PST
;
727 COPY_LYR(sylbuff
, i
, p
, '>', font_p
, size_p
);
729 sylbuff
[i
++] = (char) STR_PST_END
;
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 */
735 if (*p
== '-' || *p
== '_') {
746 if (*font_p
>= FONT_XTR
) {
767 yyerror("boxed text not allowed in lyrics");
774 yyerror("circled text not allowed in lyrics");
781 yyerror("\\: not allowed in lyric syllable");
786 yyerror("alignment not allowed in lyric syllable");
804 yyerror("too few syllables in string");
807 /* prepare for next call to this function */
810 /* return a copy of the extracted syllable */
811 return(copy_string(sylbuff
, font
, size
));
815 /* given a syllable string, return the width (in inches) of the non-lyric
816 * parts and of the actual syllable */
819 sylwidth(lyrstring
, wid_b4_syl_p
, wid_real_syl_p
, wid_after_syl_p
)
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 */
827 do_sylwidth(lyrstring
, wid_b4_syl_p
, wid_real_syl_p
, wid_after_syl_p
,
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.
838 do_sylwidth(lyrstring
, wid_b4_syl_p
, wid_real_syl_p
, wid_after_syl_p
,
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. */
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 */
857 char save
; /* temp storage */
860 if (lyrstring
== (char *) 0) {
861 *wid_b4_syl_p
= *wid_real_syl_p
= *wid_after_syl_p
= 0.0;
865 for (p
= lyrstring
; *p
!= '\0'; p
++) {
866 switch ( (unsigned) *p
& 0xff) {
868 if (compensating
== YES
) {
873 if (compensating
== NO
) {
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 <...> */
882 w1
= strwidth(lyrstring
);
883 *p
= (char) STR_PRE_END
;
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
) {
895 w2
= strwidth(lyrstring
);
900 if (compensating
== YES
) {
905 w2
= strwidth(lyrstring
);
914 /* get length of entire string */
915 w3
= strwidth(lyrstring
);
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
) {
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);
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 */
939 float pre_wid
, syl_wid
, post_wid
;
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
;
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. */
961 int vno
; /* the verse number to check */
964 struct RANGELIST
*v_p
; /* to walk through list of verse nums used */
965 struct RANGELIST
**list_p_p
; /* which list to check */
970 list_p_p
= &Above_vnumbers_used
;
973 list_p_p
= &Between_vnumbers_used
;
977 list_p_p
= &Below_vnumbers_used
;
980 pfatal("illegal place in vno_used");
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 */
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
;
1002 /* when parsing is complete, we can find out how many unique verse numbers
1003 * there were in the input */
1008 debug(4, "set_maxverses");
1010 count_verses(Above_vnumbers_used
);
1011 count_verses(Below_vnumbers_used
);
1012 count_verses(Between_vnumbers_used
);
1015 /* recursively walk down list of verse numbers used. Count them up and
1016 * free them while unwinding */
1019 count_verses(used_p
)
1021 struct RANGELIST
*used_p
;
1024 if (used_p
== (struct RANGELIST
*) 0) {
1028 count_verses(used_p
->next
);
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. */
1041 get_lyr_dflt_timeunit_ssv()
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 */
1054 reference_timeunit
= Zero
;
1055 /* if all else fails, use Score value */
1056 ssv_p
= ref_ssv_p
= &Score
;
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
) {
1063 for (staff
= staffrange_p
->begin
; staff
<= staffrange_p
->end
;
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
);
1072 ssv_p
= vvpath(staff
, 2, TIMEUNIT
);
1074 timeunit
= ssv_p
->timeunit
;
1076 /* check for consistency */
1077 if ( NE(reference_timeunit
, Zero
) ) {
1078 if ( NE(timeunit
, reference_timeunit
) ||
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");
1093 /* first time through. Now we have a timeunit
1094 * to use for default */
1095 reference_timeunit
= timeunit
;
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 */
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. */
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 */
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;
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
) {
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;
1145 if (mll_p
->str
== S_STAFF
&& mll_p
->u
.staff_p
->staffno
== staff
) {
1146 /* found the right staff data */
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;
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 */
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
) {
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
) {
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;
1185 new_list_p
= clone_gs_list(mll_p
->u
.staff_p
->groups_p
[voice
], NO
);
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
;
1193 if (gs_p
->prev
== 0) {
1194 new_list_p
= gs_p
->next
;
1197 gs_p
->prev
->next
= gs_p
->next
;
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
;
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");
1226 gs_p
->grpsyl
= GS_SYLLABLE
;
1227 if (ref_gs_p
->grpcont
== GC_REST
) {
1228 gs_p
->grpcont
= GC_SPACE
;
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
;
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
||
1258 gs_p
->notelist
[0].nslurto
> 0) {
1259 new_list_p
->grpcont
= GC_SPACE
;
1264 return (new_list_p
);