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)");