2 /* Copyright (c) 1995, 1996, 1997, 1998, 1999, 2000, 2002, 2003, 2004 by Arkkra Enterprises */
3 /* All rights reserved */
5 /* parser functions related to STUFF */
13 /* if user specifies a "til" clause on stuff with a number of measures > 0,
14 * we need to save away info about where the til clause will end, to make sure
15 * that it doesn't fall off the end of the measure or the piece. This is the
16 * struct we use to save this info. */
17 static struct TIL_INFO
{
18 char *inputfile
; /* where STUFF was defined */
19 int inputlineno
; /* where STUFF was defined */
20 int measnum
; /* number of measure in which til clause ends */
21 float count
; /* count in measure where til clause ends */
22 struct TIL_INFO
*next
; /* for linked list */
25 /* info about the STUFF currently being collected from input */
26 static int Curr_stuff_type
; /* ST_* */
27 static int Stuff_size
; /* point size of stuff text string */
28 static int Modifier
; /* TM_* for text, L_* for phrase */
29 static int Measnum
= 1; /* to check til clauses. Can't use Meas_num
30 * global because it doesn't count invisible
31 * bars but til clauses do */
32 static int Multi_adjust
; /* adjustment to Measnum to account
35 /* head and tail of list of STUFF currently being collected from input */
36 static struct STUFF
*Head_stufflist_p
;
37 static struct STUFF
*Tail_stufflist_p
;
39 /* current pedal state for each staff. YES if in the middle of doing pedal,
41 static short Pedal_state
[MAXSTAFFS
+ 1];
42 static char *Ped_begin_str
; /* will point to "\(begped)" */
43 static char *Ped_up_down_str
; /* will point to "\(pedal)" */
45 /* static functions */
46 static struct STUFF
*clone_stufflist
P((struct STUFF
*stufflist_p
,
47 int staffno
, int all
));
48 static void do_attach
P((int staffno
, int all
, struct RANGELIST
*vno_range_p
));
49 static void midi_attach
P((int staffno
, struct STAFF
*staff_p
,
50 struct RANGELIST
*vno_range_p
, int all
));
51 static void free_stufflist
P((struct STUFF
*stuff_P
));
52 static void free_tils
P((struct TIL_INFO
*til_p
));
53 static void fix_pedal
P((int staffno
, struct STUFF
*stuff_p
));
54 static void ped_order_chk
P((void));
57 /* save current stuff type value. Also check that we are in data (music)
61 set_stuff_type(stuff_type
)
66 Curr_stuff_type
= stuff_type
;
68 (void) contextcheck(C_MUSIC
, "statement");
72 /* return current stuff type */
78 return(Curr_stuff_type
);
82 /* check all the things in an input line of stuff, up to the colon,
83 * for consistency, and save interesting info away for later use. */
86 chk_stuff_header(size
, modifier
, place
, dist_usage
)
88 int size
; /* point size, or -1 if to use default */
89 int modifier
; /* TM_* for text, L_* for phrase */
91 int dist_usage
; /* SD_* */
95 debug(4, "chk_stuff_header");
97 switch (Curr_stuff_type
) {
105 if (place
!= PL_BELOW
&& place
!= PL_UNKNOWN
) {
106 yyerror("pedal must be below");
111 yyerror("can't specify size except with a font or mussym");
113 if (modifier
!= TM_NONE
&& Curr_stuff_type
!= ST_PHRASE
) {
114 l_yyerror(Curr_filename
, yylineno
,
115 "can't specify %s except with a font",
116 stuff_modifier(modifier
));
118 if (Curr_stuff_type
== ST_PHRASE
&& modifier
!= L_NORMAL
&&
119 modifier
!= L_DOTTED
&& modifier
!= L_DASHED
) {
120 l_yyerror(Curr_filename
, yylineno
,
121 "only dotted or dashed line type can be specified for phrase");
126 if (Curr_stuff_type
== ST_OCTAVE
) {
127 if (is_tab_range() == YES
) {
128 yyerror("octave not allowed on tablature staff");
130 else if(place
== PL_BETWEEN
) {
131 yyerror("octave must be above or below");
136 if (Curr_stuff_type
== ST_PHRASE
&& place
== PL_BETWEEN
) {
137 yyerror("phrase must be above, below, or omitted");
141 if (dist_usage
!= SD_NONE
) {
142 if (Curr_stuff_type
== ST_PEDAL
) {
143 yyerror("dist not allowed on pedal");
145 else if (Curr_stuff_type
== ST_PHRASE
) {
146 yyerror("dist not allowed on phrase");
148 else if (Curr_stuff_type
== ST_MIDI
) {
149 yyerror("dist not allowed on midi");
152 if (place
== PL_BETWEEN
) {
153 yyerror("dist not allowed with 'between'");
157 /* Save the modifier value.
158 * Have to set this before calling dflt_place() */
161 /* fill in default values if user didn't specify */
162 if (place
== PL_UNKNOWN
) {
163 place
= dflt_place();
167 Place
= (short) place
;
169 /* make sure current list of stuff is empty */
170 Head_stufflist_p
= Tail_stufflist_p
= (struct STUFF
*) 0;
174 /* return default value for place depending on value of Curr_stuff_type */
180 switch (Curr_stuff_type
) {
186 yyerror("must specify above or below with octave");
187 /* arbitrarily return above. If we leave it as unknown,
188 * we can get double error messages in some cases */
192 /* stays unknown at this point */
196 if (Modifier
== TM_ANALYSIS
|| Modifier
== TM_FIGBASS
) {
199 /* default for everything else is above */
205 /* Add a space padding to a string (except if is it boxed).
206 * If padding was added, free the passed-in string and return the padded string,
207 * else return the string as is. The incoming string
208 * is expected to already be converted to font/size/string
209 * internal format by this time, although still in input ASCII form.
213 pad_string(string
, modifier
)
216 int modifier
; /* TM_* */
219 char *padded_string
; /* string with 1-space padding at end */
220 char *str_p
; /* walk through padded_string */
221 int len
; /* length of string */
222 int last_was_backslash
; /* YES/NO */
223 int count_backslashed
; /* YES/NO if to count backslashed or
224 * unbackslashed colons */
225 int colons
; /* how many colons found */
226 int extra
; /* how many extra bytes to malloc */
228 /* Boxed and circled strings don't get any extra padding,
229 * so we can use what we have */
230 if (string
[2] == '\\' && (string
[3] == '[' || string
[3] == '{')) {
234 /* Make a new copy with a space at the end.
235 * But if the string ends in the middle of a pile,
236 * we need to implicitly end the pile before adding the space.
237 * Since the string is still in ASCII form,
238 * we have to count up the number of colons
239 * to see if we are mid-pile. In chord/analysis/figbass
240 * we need to count unbackslashed colon,
241 * otherwise backslashed.*/
242 count_backslashed
= (IS_CHORDLIKE(modifier
) ? NO
: YES
);
243 /* figbass implicitly begins with a pile */
244 colons
= (modifier
== TM_FIGBASS ?
1 : 0);
245 last_was_backslash
= NO
;
246 for (str_p
= string
+ 2; *str_p
!= '\0'; str_p
++) {
247 if (last_was_backslash
== YES
) {
248 if (*str_p
== ':' && count_backslashed
== YES
) {
251 last_was_backslash
= NO
;
254 if (*str_p
== ':' && count_backslashed
== NO
) {
257 last_was_backslash
= (*str_p
== '\\' ? YES
: NO
);
261 /* If odd number of colons, we are mid-pile. Will need
262 * add extra byte to hold the colon to implicitly end the
263 * pile, and if it needs to be a backslashed colon,
264 * another extra byte for that. */
266 extra
= (count_backslashed
== YES ?
2 : 1);
272 len
= strlen(string
);
274 /* +2 is for space/null at end */
275 MALLOCA(char, padded_string
, len
+ 2 + extra
);
276 (void) memcpy(padded_string
, string
, len
);
277 str_p
= padded_string
+ len
;
279 /* add implicit end-pile if needed */
287 /* now add space padding */
291 return(padded_string
);
295 /* check a "stuff" item and add to list */
298 add_stuff_item(start_count
, start_steps
, gracebackup
, string
, bars
, count
,
301 double start_count
; /* where in measure to start this stuff */
302 double start_steps
; /* offset by this many stepsizes */
303 int gracebackup
; /* how many grace notes to back up from start */
304 char *string
; /* what to print */
305 int bars
; /* how many bar lines to cross with this stuff */
306 double count
; /* how many beats into last measure */
307 int dist
; /* dist for this specific STUFF, to override param */
308 int dist_usage
; /* meaning of dist, SD_* */
311 struct STUFF
*new_p
; /* where to store STUFF */
312 struct TIL_INFO
*til_info_p
; /* to save info about til clause */
313 int len
; /* length of stuff text string */
314 char *padded_string
; /* string with 1-space padding at end */
315 char lch
; /* last character of string */
318 if (bars
!= 0 || count
!= 0.0) {
319 /* has a "til" clause. Check if that is valid */
320 if (Curr_stuff_type
== ST_MUSSYM
) {
321 if (string
== (char *) 0) {
322 yyerror("missing string");
326 /* not yet changed to internal form, need to compare
328 if ((strcmp(string
+ 2, "tr") != 0) &&
329 (strcmp(string
+ 2, "\\(tr)") != 0)) {
330 yyerror("til not allowed on mussym except on trills");
334 else if (Curr_stuff_type
== ST_PEDAL
) {
335 yyerror("til not allowed on pedal");
338 else if (Curr_stuff_type
== ST_MIDI
) {
339 yyerror("til not allowed on midi");
342 if (Curr_stuff_type
!= ST_PHRASE
&&
343 (Modifier
== TM_CHORD
|| Modifier
== TM_ANALYSIS
) ) {
344 l_yyerror(Curr_filename
, yylineno
,
345 "til not allowed with %s",
346 stuff_modifier(Modifier
));
350 if (count
> Score
.timenum
+ 1) {
351 yyerror("'til' value must be <= numerator of time signature + 1");
354 if (count
< start_count
) {
355 yyerror("til value must be >= start value");
361 /* doesn't have a "til" clause. Check if one is required */
362 if (Curr_stuff_type
== ST_CRESC
||
363 Curr_stuff_type
== ST_DECRESC
) {
364 yyerror("til required on cresc/decresc");
368 if (start_count
> Score
.timenum
+ 1) {
369 yyerror("beat offset must be <= numerator of time signature + 1");
372 if (Curr_stuff_type
== ST_CRESC
|| Curr_stuff_type
== ST_DECRESC
) {
373 if (string
!= (char *) 0) {
374 yyerror("string not allowed with cresc/decresc");
379 else if (Curr_stuff_type
== ST_PHRASE
) {
380 if (string
!= (char *) 0) {
381 yyerror("string not allowed with phrase");
385 else if (Curr_stuff_type
== ST_PEDAL
) {
386 if ( (string
!= (char *) 0)
387 && (strcmp(string
+ 2, "\\(endped)") != 0) ) {
388 yyerror("pedal string must be either blank or *");
393 if (string
== (char *) 0) {
394 yyerror("string is required");
399 if (gracebackup
!= 0 && Place
== PL_BETWEEN
) {
400 yyerror("grace backup not allowed with 'between'");
403 /* we can't deal with step offset on phrase marks very well,
404 * so warn and ignore if we get one */
405 if (start_steps
!= 0.0 && Curr_stuff_type
== ST_PHRASE
) {
406 l_warning(Curr_filename
, yylineno
, "step offset ignored on phrase mark");
410 switch (Curr_stuff_type
) {
415 /* the text-type stuffs are supposed to have a 1-space padding
416 * at the end of them */
417 if (bars
!= 0 || count
!= 0.0) {
418 /* don't add padding if has wavy or solid line
420 lch
= last_char(string
);
421 if (lch
== '~' || lch
== '_') {
425 string
= pad_string(string
, Modifier
);
429 /* in mussym, user can specify things without the usual
430 * \(---) convention. Change to include them */
431 if (string
[2] == '\\' && string
[3] == '(') {
432 /* if user unnecessarily put in the \(--), leave it */
436 len
= strlen(string
+ 2);
437 MALLOCA(char, padded_string
, len
+ 6);
438 (void) sprintf(padded_string
, "%c%c\\(%s)", FONT_TR
, DFLT_SIZE
,
441 string
= padded_string
;
448 /* fill in a new STUFF struct with appropriate info */
449 new_p
= newSTUFF(string
, dist
, dist_usage
, start_count
, start_steps
,
450 gracebackup
, bars
, count
,
451 Curr_stuff_type
, Modifier
, Place
, Curr_filename
, yylineno
);
453 /* if bars > 0, need to save away til info for later error
456 CALLOC(TIL_INFO
, til_info_p
, 1);
457 til_info_p
->measnum
= Measnum
+ bars
;
458 til_info_p
->count
= count
;
459 til_info_p
->inputfile
= new_p
->inputfile
;
460 til_info_p
->inputlineno
= new_p
->inputlineno
;
461 til_info_p
->next
= Til_info_list_p
;
462 Til_info_list_p
= til_info_p
;
465 /* above/between go on the head of the list, below goes on the
466 * tail of the list, so that things come out in the right order.
467 * Midi always goes at the end */
468 if (Place
== PL_BELOW
|| Curr_stuff_type
== ST_MIDI
) {
469 /* link onto list tail */
470 if ( Tail_stufflist_p
== (struct STUFF
*) 0) {
471 Head_stufflist_p
= new_p
;
474 Tail_stufflist_p
->next
= new_p
;
476 Tail_stufflist_p
= new_p
;
479 /* link onto head of list */
480 new_p
->next
= Head_stufflist_p
;
481 Head_stufflist_p
= new_p
;
482 if (Tail_stufflist_p
== (struct STUFF
*) 0) {
483 Tail_stufflist_p
= new_p
;
489 /* return YES if given string consists entirely of the specific music symbol */
490 /* the string should be in the internal format of font/size/string */
493 string_is_sym(string
, sym
, symfont
)
495 char *string
; /* which string to check */
496 int sym
; /* check for this music symbol */
497 int symfont
; /* FONT_MUSIC* */
503 if (string
== (char *) 0) {
509 if (next_str_char(&string
, &font
, &size
) != sym
) {
512 if (font
!= symfont
) {
515 if (next_str_char(&string
, &font
, &size
) == '\0') {
522 /* connect a list of STUFF to a STAFF. If there is already something on
523 * that STAFF's STUFF list, attach at the end or beginning as appropriate
524 * depending on place. */
530 struct SVRANGELIST
*svr_p
; /* to walk through Svrangelist */
531 struct RANGELIST
*r_p
; /* to walk through staff range list */
535 debug(4, "attach_stuff");
537 /* make sure we've got STAFF structs for this measure */
540 for (svr_p
= Svrangelist_p
; svr_p
!= (struct SVRANGELIST
*) 0;
541 svr_p
= svr_p
->next
) {
542 for (r_p
= svr_p
->stafflist_p
; r_p
!= (struct RANGELIST
*) 0;
545 for (staffno
= r_p
->begin
; staffno
<= r_p
->end
546 && staffno
<= MAXSTAFFS
; staffno
++) {
547 do_attach(staffno
, r_p
->all
, svr_p
->vnolist_p
);
549 if (Place
== PL_BETWEEN
) {
550 /* between has 2 staffs in its range,
551 * but stuff is only associated
552 * with the top staff */
561 /* have made copies of stuff for each staff that gets one, with
562 * the proper font/size etc, so need to free master stufflist copy */
563 free_stufflist(Head_stufflist_p
);
567 /* Attach STUFF for a specific staff. */
570 do_attach(staffno
, all
, vno_range_p
)
574 struct RANGELIST
*vno_range_p
;
577 struct STAFF
*staff_p
; /* where to attach STUFF */
578 struct STUFF
*stufflist_p
; /* current copy of STUFF list */
581 if (staffno
> Score
.staffs
) {
582 l_yyerror(Head_stufflist_p
->inputfile
,
583 Head_stufflist_p
->inputlineno
,
584 "staff number out of range");
588 staff_p
= Staffmap_p
[staffno
]->u
.staff_p
;
590 if (Place
== PL_BETWEEN
) {
591 if (staffno
+ 1 > Score
.staffs
) {
592 /* will have already exclaimed about
593 * this error before, so no need to print message,
594 * but better skip next check */
598 /* if either staff of a between is invisible,
599 * throw this stuff away */
600 if (svpath(staffno
, VISIBLE
)->visible
== NO
||
602 VISIBLE
)->visible
== NO
) {
607 /* handle MIDI stuff specially */
608 if (Curr_stuff_type
== ST_MIDI
) {
610 /* need to find top visible staff/voice to attach to */
611 int s
; /* staff number */
612 int v
; /* voice number */
613 struct RANGELIST range
;
615 v
= 1; /* avoid bogus "used before set" warning */
616 for (s
= 1; s
<= MAXSTAFFS
; s
++) {
617 if (svpath(s
, VISIBLE
)->visible
== YES
) {
618 for (v
= 1; v
<= MAXVOICES
; v
++) {
619 if (vvpath(s
, v
, VISIBLE
)->visible
== YES
) {
623 if (v
<= MAXVOICES
) {
628 if (s
> MAXSTAFFS
|| v
> MAXVOICES
) {
629 pfatal("failed to find top visible staff/voice");
631 /* make a special RANGELIST for this */
632 range
.begin
= range
.end
= v
;
635 midi_attach(s
, Staffmap_p
[s
]->u
.staff_p
, &range
, all
);
638 midi_attach(staffno
, staff_p
, vno_range_p
, all
);
643 /* make the copy for this staff from master copy */
644 stufflist_p
= clone_stufflist(Head_stufflist_p
, staffno
, all
);
646 if (Curr_stuff_type
== ST_PEDAL
) {
647 fix_pedal(staffno
, stufflist_p
);
650 connect_stuff(staff_p
, stufflist_p
);
655 /* attach MIDI stuff. This is slightly different than other stuff because
656 * it can be applied to one or both voices. */
659 midi_attach(staffno
, staff_p
, vno_range_p
, all
)
661 int staffno
; /* attach to this staff number */
662 struct STAFF
*staff_p
; /* attach to this staff struct */
663 struct RANGELIST
*vno_range_p
;
664 int all
; /* if associated with "all" */
667 struct RANGELIST
*r_p
; /* walk through vno_range_p */
668 int vno
; /* voice number */
669 struct STUFF
*stufflist_p
; /* copy of stuff */
670 struct STUFF
*st_p
; /* walk through stufflist_p */
674 /* do for each voice that MIDI stuff applies to */
675 for (r_p
= vno_range_p
; r_p
!= (struct RANGELIST
*) 0; r_p
= r_p
->next
) {
676 for (vno
= r_p
->begin
; vno
<= r_p
->end
; vno
++) {
678 /* make the copy for this staff from master copy */
679 stufflist_p
= clone_stufflist(Head_stufflist_p
,
682 /* fix up place based on voice number */
694 pfatal("illegal vno for midi");
696 place
= PL_UNKNOWN
; /* avoid "used before set" warning */
699 for (st_p
= stufflist_p
; st_p
!= (struct STUFF
*) 0;
704 connect_stuff(staff_p
, stufflist_p
);
710 /* connect a new stuff list into an existing stuff list. Add below stuff and
711 * MIDI stuff to the end of the list,
712 * and others to beginning of list, but make sure any
713 * "above all" comes after any above non-all, and that any below non-all
714 * comes before any "below all."
718 connect_stuff(staff_p
, stufflist_p
)
720 struct STAFF
*staff_p
; /* connect to stuff off of this staff */
721 struct STUFF
*stufflist_p
; /* connect this list of stuff */
724 struct STUFF
*st_p
; /* to find link place in STUFF list */
725 struct STUFF
*s_p
; /* to find end of stufflist_p */
726 struct STUFF
**ins_p_p
; /* where to insert in list */
729 if (staff_p
== (struct STAFF
*) 0 || stufflist_p
== (struct STUFF
*) 0) {
733 if (staff_p
->stuff_p
== (struct STUFF
*) 0) {
734 /* no list before, so attach this one
735 * directly to STAFF */
736 staff_p
->stuff_p
= stufflist_p
;
739 else if (Place
== PL_BELOW
|| stufflist_p
->stuff_type
== ST_MIDI
) {
740 /* if this set of stuff isn't associated with
741 * "all", then it goes before any below "all" stuff */
742 if (stufflist_p
->all
== NO
) {
743 for (ins_p_p
= &(staff_p
->stuff_p
);
744 *ins_p_p
!= (struct STUFF
*) 0;
745 ins_p_p
= &((*ins_p_p
)->next
)) {
746 if ( (*ins_p_p
)->place
== PL_BELOW
&&
747 (*ins_p_p
)->all
== YES
) {
751 /* find end of list to be inserted */
752 for (s_p
= stufflist_p
; s_p
->next
!= (struct STUFF
*) 0;
758 s_p
->next
= *ins_p_p
;
759 *ins_p_p
= stufflist_p
;
763 /* goes at end of list. find the end */
764 for (st_p
= staff_p
->stuff_p
;
765 st_p
->next
!= (struct STUFF
*)0;
770 /* connect in the new list */
771 st_p
->next
= stufflist_p
;
775 /* find end of new list */
776 for (s_p
= stufflist_p
;
777 s_p
->next
!= (struct STUFF
*) 0;
782 if (stufflist_p
->all
== NO
) {
783 /* goes at the head of the list */
784 s_p
->next
= staff_p
->stuff_p
;
785 staff_p
->stuff_p
= stufflist_p
;
788 /* goes before any existing above all */
789 for (ins_p_p
= &(staff_p
->stuff_p
);
790 *ins_p_p
!= (struct STUFF
*) 0;
791 ins_p_p
= &((*ins_p_p
)->next
)) {
792 if ( (*ins_p_p
)->place
== PL_ABOVE
&&
793 (*ins_p_p
)->all
== YES
) {
797 /* find end of list to be inserted */
798 for (s_p
= stufflist_p
; s_p
->next
!= (struct STUFF
*) 0;
804 s_p
->next
= *ins_p_p
;
805 *ins_p_p
= stufflist_p
;
811 /* given a list of STUFF, return a clone of the list */
813 static struct STUFF
*
814 clone_stufflist(stufflist_p
, staffno
, all
)
816 struct STUFF
*stufflist_p
; /* what stuff to clone */
817 int staffno
; /* which staff, to get proper point size */
818 int all
; /* YES if was "above all" or "below all" */
821 struct STUFF
*new_p
; /* copy of STUFF */
822 char *newstring
; /* copy of text string */
828 if (stufflist_p
== (struct STUFF
*) 0) {
829 return( (struct STUFF
*) 0 );
832 /* make copy of string with appropriate font and size */
833 if (stufflist_p
->string
!= (char *) 0) {
834 switch(stufflist_p
->stuff_type
) {
839 Stuff_size
= DFLT_SIZE
;
853 /* figure out the proper size if not already determined */
854 if (Stuff_size
< 0) {
859 size
= svpath(staffno
, SIZE
)->size
;
866 /* determine fontfamily and font if not already known */
867 if (Curr_family
== FAMILY_DFLT
) {
869 fontfamily
= Score
.fontfamily
;
872 fontfamily
= svpath(staffno
, FONTFAMILY
)->
877 fontfamily
= Curr_family
;
880 /* clone text string */
881 newstring
= copy_string(stufflist_p
->string
+ 2, font
, size
);
882 if (IS_CHORDLIKE(Modifier
)) {
883 newstring
= modify_chstr(newstring
, Modifier
);
885 fix_string(newstring
, fontfamily
+ font
, size
,
886 stufflist_p
->inputfile
, stufflist_p
->inputlineno
);
887 if (Modifier
== TM_FIGBASS
|| Modifier
== TM_ANALYSIS
) {
888 newstring
= acc_trans(newstring
);
892 newstring
= (char *) 0;
895 /* create and fill in clone of stuff, then return it */
896 new_p
= newSTUFF(newstring
, stufflist_p
->dist
,
897 stufflist_p
->dist_usage
,
898 stufflist_p
->start
.count
,
899 stufflist_p
->start
.steps
,
900 stufflist_p
->gracebackup
,
901 stufflist_p
->end
.bars
, stufflist_p
->end
.count
,
902 stufflist_p
->stuff_type
, stufflist_p
->modifier
,
903 stufflist_p
->place
, stufflist_p
->inputfile
,
904 stufflist_p
->inputlineno
);
905 new_p
->all
= (short) all
;
906 new_p
->next
= clone_stufflist(stufflist_p
->next
, staffno
, all
);
911 /* allocate a STUFF and fill in all the values given. Initialize carry fields
912 * and "all" to NO. Leave coordinates and next link as 0.
913 * Note that the string pointer
914 * is copied; it does not make a copy of the string itself, so never call this
915 * function more than once with the same string--make a copy. */
918 newSTUFF(string
, dist
, dist_usage
, start_count
, start_steps
, gracebackup
, bars
, count
,
919 stuff_type
, modifier
, place
, inputfile
, inputlineno
)
921 char *string
; /* text string of stuff */
922 int dist
; /* dist for this STUFF to override dist parameter */
923 int dist_usage
; /* meaning of dist, SD_* */
924 double start_count
; /* count at which to begin stuff */
925 double start_steps
; /* offset by this many steps */
926 int gracebackup
; /* how many grace notes to back up from start */
927 int bars
; /* bars in "til" clasue */
928 double count
; /* counts in "til" clause */
929 int stuff_type
; /* ST_* */
930 int modifier
; /* TM_* */
931 int place
; /* PL_* */
932 char *inputfile
; /* which file stuff was defined in */
933 int inputlineno
; /* where stuff was defined in input file */
936 struct STUFF
*new_p
; /* the new STUFF to fill in */
939 CALLOC(STUFF
, new_p
, 1);
940 new_p
->string
= string
;
941 new_p
->start
.count
= start_count
;
942 new_p
->start
.steps
= start_steps
;
943 new_p
->gracebackup
= (short) gracebackup
;
944 new_p
->dist
= (short) dist
;
945 new_p
->dist_usage
= (short) dist_usage
;
946 new_p
->end
.bars
= (short) bars
;
947 new_p
->end
.count
= count
;
948 new_p
->stuff_type
= (short) stuff_type
;
949 new_p
->modifier
= (short) modifier
;
950 new_p
->place
= (short) place
;
951 new_p
->carryin
= new_p
->carryout
= new_p
->all
= NO
;
952 new_p
->costuff_p
= 0;
953 new_p
->inputfile
= inputfile
;
954 new_p
->inputlineno
= (short) inputlineno
;
960 /* recursively free up a stufflist and any strings hanging off of it */
963 free_stufflist(stuff_p
)
965 struct STUFF
*stuff_p
;
968 if (stuff_p
== (struct STUFF
*) 0 ) {
972 free_stufflist(stuff_p
->next
);
973 if (stuff_p
->string
!= (char *) 0) {
974 FREE(stuff_p
->string
);
980 /* at each bar line, see if there are any "til" clauses that are supposed
981 * to end in this measure. If so, make sure they end within the time
982 * signature for this measure. */
988 struct TIL_INFO
*til_info_p
; /* to index thru list */
989 struct TIL_INFO
**del_place_p_p
; /* for deleting from list */
990 struct TIL_INFO
*one2free_p
; /* pointer to which element
993 debug(2, "meas_chk_stuff");
995 /* update measure number to conpensate for any multirests */
996 Measnum
+= Multi_adjust
;
999 /* go through list of in-progress til clauses */
1000 for (til_info_p
= Til_info_list_p
, del_place_p_p
= &Til_info_list_p
;
1001 til_info_p
!= (struct TIL_INFO
*) 0; ) {
1003 if (til_info_p
->measnum
== Measnum
) {
1005 /* at measure where this til clause ends */
1006 /* check if within time signature */
1007 if (til_info_p
->count
> Score
.timenum
+ 1.0) {
1008 l_yyerror(til_info_p
->inputfile
,
1009 til_info_p
->inputlineno
,
1010 "beats in 'til' clause must be <= numerator of time signature + 1 of the measure in which the 'til' clause ends (i.e., <= %d)",
1014 /* this one has been taken care of: delete from list */
1015 *del_place_p_p
= til_info_p
->next
;
1016 one2free_p
= til_info_p
;
1018 else if (til_info_p
->measnum
< Measnum
) {
1019 /* must have ended inside a multirest, so delete
1021 *del_place_p_p
= til_info_p
->next
;
1022 one2free_p
= til_info_p
;
1025 /* this one stays on the list for now, so move pointer
1026 * to where to potentially delete to next element */
1027 del_place_p_p
= &(til_info_p
->next
);
1028 one2free_p
= (struct TIL_INFO
*) 0;
1031 /* have to move to next element
1032 * before freeing the current one */
1033 til_info_p
= til_info_p
->next
;
1035 if (one2free_p
!= (struct TIL_INFO
*) 0) {
1040 /* update number of measures. */
1043 /* make sure pedal marks are in proper order */
1048 /* adjust number of measures to account for multirests. Called when there is
1049 * a multirest. Saved the number of measures in the multirest (minus 1 since
1050 * the barline at the end will count for one measure) */
1055 int nmeas
; /* number of measures in multirest */
1058 /* subtract 1 to account for the fact that at the bar line at the
1059 * end of the multirest we will peg the measure counter */
1060 Multi_adjust
= nmeas
- 1;
1064 /* handle pedal going into endings. When we hit a first ending, save the
1065 * state of the pedal for all staffs. On subsequent endings in the set,
1066 * reset the pedal state to what it was at the beginning of the first ending.
1067 * At the endending, go back to normal operation. This is similar to
1068 * the saveped() function used at print time. */
1071 ped_endings(endingloc
)
1073 int endingloc
; /* STARTITEM, INITEM, etc */
1076 register int s
; /* staff index */
1079 if (endingloc
== STARTITEM
) {
1080 if (Ped_snapshot
[0] == YES
) {
1082 /* starting 2nd ending: restore pedal state as it was
1083 * at beginning of first ending */
1084 for (s
= 1; s
<= MAXSTAFFS
; s
++) {
1085 Pedal_state
[s
] = Ped_snapshot
[s
];
1090 /* starting a set of endings,
1091 * need to save pedal state at this
1092 * point so we can carry it into subsequent endings */
1093 for (s
= 1; s
<= Score
.staffs
; s
++) {
1094 Ped_snapshot
[s
] = Pedal_state
[s
];
1096 /* make sure any remaining staffs are set to pedal off,
1097 * in case user increases the number of staffs
1098 * during the endings... */
1099 for ( ; s
<= MAXSTAFFS
; s
++) {
1100 Ped_snapshot
[s
] = NO
;
1103 /* mark that we now have a snapshot */
1104 Ped_snapshot
[0] = YES
;
1108 else if (endingloc
== ENDITEM
) {
1109 /* at end of endings, discard snapshot of pedal states */
1110 Ped_snapshot
[0] = NO
;
1115 /* When all input has been processed, or when changing the number
1116 * of staffs, we better not have any 'til' clauses
1117 * still unfinished. If we do, print a warning message. */
1120 chk4dangling_til_clauses(boundary_desc
)
1122 char *boundary_desc
; /* "the end of the song" or
1123 * "a change in number of staffs" */
1126 struct TIL_INFO
*til_info_p
;
1129 debug(2, "chk4dangling_til_clauses");
1131 /* Go through the whole list of remaining til clauses,
1132 * and print a warning message for each. */
1133 for (til_info_p
= Til_info_list_p
; til_info_p
!= (struct TIL_INFO
*) 0;
1134 til_info_p
= til_info_p
->next
) {
1136 /* If right on the boundary or spills over only a very tiny
1137 * amount, don't bother to complain */
1138 if (til_info_p
->measnum
- Measnum
== 0
1139 && til_info_p
->count
< .001) {
1143 l_warning(til_info_p
->inputfile
, til_info_p
->inputlineno
,
1144 "'til' clause extends beyond %s by %dm + %.3f",
1145 boundary_desc
, til_info_p
->measnum
- Measnum
,
1150 free_tils(Til_info_list_p
);
1151 Til_info_list_p
= (struct TIL_INFO
*) 0;
1155 /* recursively free a list of TIL_INFO structs */
1160 struct TIL_INFO
*til_p
; /* free this list */
1163 if (til_p
== (struct TIL_INFO
*) 0) {
1167 free_tils(til_p
->next
);
1172 /* user only has to specify when pedal marks end. We deduce from current
1173 * pedal state whether a pedal mark is begin or up/down. This gets called
1174 * whenever we have a list of pedal STUFFs. Later we enforce that pedal
1175 * marks are put in in ascending order only, so that if user enters more
1176 * than one pedal line for the same staff, that will be handled properly. */
1179 fix_pedal(staffno
, stuff_p
)
1181 int staffno
; /* pedal is for this staff */
1182 struct STUFF
*stuff_p
; /* list of pedal mark info */
1185 /* walk through list of pedal marks */
1186 for ( ; stuff_p
!= (struct STUFF
*) 0; stuff_p
= stuff_p
->next
) {
1188 if (stuff_p
->string
== (char *) 0) {
1189 /* no star, so have to deduce state */
1191 if (Pedal_state
[staffno
] == NO
) {
1192 /* pedal currently off, so begin pedal */
1193 Pedal_state
[staffno
] = YES
;
1194 stuff_p
->string
= copy_string(Ped_begin_str
+ 2,
1195 (int) Ped_begin_str
[0],
1196 (int) Ped_begin_str
[1]);
1199 /* pedal currently down, so pedal up/down */
1200 stuff_p
->string
= copy_string(Ped_up_down_str
+ 2,
1201 (int) Ped_up_down_str
[0],
1202 (int) Ped_up_down_str
[1]);
1206 else if (Pedal_state
[staffno
] == NO
) {
1207 yyerror("can't end pedal -- none in progress");
1211 /* user gave star, so end pedal */
1212 Pedal_state
[staffno
] = NO
;
1218 /* reset pedal states for all staffs. This should be called at init time
1219 * and at any time when the number of staffs changes. This function also
1220 * initializes the Ped_begin_str and Ped_up_down_str. */
1226 static int first_time
= YES
; /* flag if function called before */
1227 register int s
; /* index through staffs */
1230 /* mark pedal off for all staffs */
1231 for (s
= 1; s
<= Score
.staffs
; s
++) {
1232 Pedal_state
[s
] = NO
;
1234 Ped_snapshot
[0] = NO
;
1236 /* the first time this function is called, initialize the strings
1237 * for pedal begin and pedal end. We just have one copy of these
1238 * and then make as many copies from these as necessary */
1239 if (first_time
== YES
) {
1241 Ped_begin_str
= copy_string("\\(begped)", FONT_MUSIC
,
1243 Ped_up_down_str
= copy_string("\\(pedal)", FONT_MUSIC
,
1245 fix_string(Ped_begin_str
, FONT_MUSIC
, DFLT_SIZE
,
1247 fix_string(Ped_up_down_str
, FONT_MUSIC
, DFLT_SIZE
,
1253 /* fill in rehearsal mark string. This doesn't go in a STUFF, but it's
1254 * sort of like stuff and there didn't seem to be any more appropriate file for
1258 static int Reh_let
= 0; /* current value of rehearsal letter. 0 == "A",
1259 * 25 == "Z", 26 == "AA", etc to 701 == "ZZ" */
1260 static int Reh_num
= 1; /* current value of rehearsal number */
1264 set_reh_string(bar_p
, fontfamily
, font
, size
, string
)
1266 struct BAR
*bar_p
; /* which bar gets the rehearsal mark */
1267 int fontfamily
; /* what font family to use, or FAMILY_DFLT
1268 * if to use current default */
1269 int font
; /* what font to use, or FONT_UNKNOWN if to use the
1270 * current default font */
1271 int size
; /* font size to use, or -1 if to use current default */
1272 char *string
; /* string for rehearsal mark */
1275 char reh_str
[12]; /* temporary buff for string version of
1276 * rehearsal number or letter */
1277 static int reh_size
= DFLT_SIZE
; /* size to use for reh marks */
1278 static int reh_family
= FAMILY_DFLT
; /* font family to use */
1279 static int reh_font
= FONT_TB
; /* font to use */
1282 /* if first time through, init the font family to the score family */
1283 if (reh_family
== FAMILY_DFLT
) {
1284 reh_family
= Score
.fontfamily
;
1287 /* if user specified a new size, save that */
1290 yyerror("reh mark size too large");
1298 /* if user specified new font or font family, save that */
1299 if (font
!= FONT_UNKNOWN
) {
1302 if (fontfamily
!= FAMILY_DFLT
) {
1303 reh_family
= fontfamily
;
1306 switch(bar_p
->reh_type
) {
1309 /* get string version of current rehearsal number, and
1311 bar_p
->reh_string
= copy_string(num2str(Reh_num
++) + 2,
1312 reh_family
+ reh_font
, reh_size
);
1316 /* Get string version of current rehearsal letter.
1317 * Start with A-Z, then AA, AB, AC, ... BA, BB, ... up to ZZ.
1320 /* 1-letter long mark */
1321 (void) sprintf(reh_str
, "%c", Reh_let
+ 'A');
1323 else if (Reh_let
< 27 * 26) {
1324 /* 2-letter long mark */
1325 (void) sprintf(reh_str
, "%c%c",
1326 (Reh_let
/ 26) + 'A' - 1, (Reh_let
% 26) + 'A');
1329 ufatal("too many rehearsal letters!");
1331 bar_p
->reh_string
= copy_string(reh_str
,
1332 reh_family
+ reh_font
, reh_size
);
1333 /* increment for next time around */
1338 /* get string version of current measure number */
1339 bar_p
->reh_string
= copy_string(num2str(Meas_num
) + 2,
1340 reh_family
+ reh_font
, reh_size
);
1344 /* user-specified string */
1345 bar_p
->reh_string
= fix_string(string
,
1346 reh_family
+ reh_font
, reh_size
,
1347 Curr_filename
, yylineno
);
1354 pfatal("set_reh_string passed bad value");
1360 /* Set rehearsal letter or number to user-specified value.
1361 * If the current bar has a rehearsal mark of the type being changed,
1362 * also replace its current mark with the changed one. This allows user
1367 * and get the same results, which is consistent with how mnum= setting
1372 init_reh(rehnumber
, rehletter
, mainbar_p
)
1374 int rehnumber
; /* New value for Reh_num or negative if setting Reh_let */
1375 char *rehletter
; /* "A" to "ZZ" or null if setting number */
1376 struct MAINLL
*mainbar_p
; /* points to the current BAR */
1380 char *oldstr
; /* previous reh_string */
1382 if (mainbar_p
== 0 || mainbar_p
->str
!= S_BAR
) {
1383 pfatal("bad mainbar_p passed to init_reh");
1385 bar_p
= mainbar_p
->u
.bar_p
;
1386 oldstr
= bar_p
->reh_string
;
1388 if (rehnumber
>= 0) {
1389 Reh_num
= rehnumber
;
1390 /* If this bar has a rehearsal number on this bar,
1391 * replace it, and free the old one. */
1392 if (bar_p
->reh_type
== REH_NUM
) {
1393 set_reh_string(bar_p
, FAMILY_DFLT
, FONT_UNKNOWN
, -1,
1399 if (rehletter
!= 0) {
1400 /* Letter is stored internally as a number,
1401 * which is then converted, so we have to convert in reverse.
1402 * We only allow "A" through "ZZ" */
1403 if (isupper(rehletter
[0]) && rehletter
[1] == '\0') {
1404 Reh_let
= rehletter
[0] - 'A';
1406 else if (isupper(rehletter
[0]) && isupper(rehletter
[1])
1407 && rehletter
[2] == '\0') {
1408 Reh_let
= 26 + (rehletter
[1] - 'A')
1409 + (rehletter
[0] - 'A') * 26;
1412 yyerror("rehearsal letter setting must be \"A\" through \"ZZ\"");
1415 /* If this bar has a rehearsal letter on this bar,
1416 * replace it, and free the old one. */
1417 if (bar_p
->reh_type
== REH_LET
) {
1418 set_reh_string(bar_p
, FAMILY_DFLT
, FONT_UNKNOWN
, -1,
1426 /* go through all stuff lists and verify that pedal marks are given in
1427 * ascending order. If not, error. Some code in both parse and
1428 * placement phases requires that pedal marks be in order. */
1435 struct STUFF
*stuff_p
; /* walk through stuff list */
1436 float last_ped_count
; /* count where last pedal occurred */
1437 int last_backup
; /* gracebackup of last pedal */
1440 /* check every staff */
1441 for (staffno
= 1; staffno
<= Score
.staffs
; staffno
++) {
1443 /* initialize for current staff */
1444 last_ped_count
= -1.0;
1447 /* go through stuff list for current staff, looking for pedal */
1448 for (stuff_p
= Staffmap_p
[staffno
]->u
.staff_p
->stuff_p
;
1449 stuff_p
!= (struct STUFF
*) 0;
1450 stuff_p
= stuff_p
->next
) {
1451 if (stuff_p
->stuff_type
== ST_PEDAL
) {
1453 /* found a pedal. Make sure it is later than
1454 * the previous pedal */
1455 if (stuff_p
->start
.count
< last_ped_count
||
1456 (stuff_p
->start
.count
1458 && stuff_p
->gracebackup
1460 l_yyerror(stuff_p
->inputfile
,
1461 stuff_p
->inputlineno
,
1462 "pedal must be specified in ascending order");
1463 /* no need to print error more than
1464 * once if multiple errors */
1468 /* keep track of where this pedal is, for
1469 * comparing with the next one */
1470 last_ped_count
= stuff_p
->start
.count
;
1471 last_backup
= stuff_p
->gracebackup
;
1478 /* Translate STUFF text modifier to a printable string. */
1481 stuff_modifier(modifier
)
1497 return("(no modifier)");
1499 return("(invalid modifier)");