chiark / gitweb /
Import upstream version 5.3.
[mup] / mup / mup / check.c
1
2 /* Copyright (c) 1995, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006 by Arkkra Enterprises */
3 /* All rights reserved */
4
5 /* functions for checking for various classes of errors such as
6  * values out of range, or trying to do something in an illegal context.
7  * Also contains the code to combine multiple measures of rests into
8  * multirests. */
9
10 #include "defines.h"
11 #include "structs.h"
12 #include "globals.h"
13
14
15 static struct MAINLL *add_pre_meas P((struct MAINLL *insert_p, int start,
16                 int end, int add_bar));
17 static int check_all_rests P((struct STAFF *staff_p, int count));
18 static void do_combine P((struct MAINLL *begin_p, struct MAINLL *end_p,
19                 int nummeas, int min_combine));
20 static int valid_mark_item P((int mark, int place));
21 static void mv_accs P((struct MAINLL *mll_p));
22 static void move_xoct P((struct STUFF *stuff_p, struct MAINLL *newfirst_p,
23                 int staffno, int bars, int start));
24 static void addped P((struct STUFF *pedal_p, struct MAINLL *mll_p));
25
26
27 \f
28
29 /* give error message if given number is not within specified range. */
30 /* return NO if out of range, YES if okay */
31
32 /* once upon a time, there was the rangecheck function, and it got called
33  * many times. Then midi support was added and that code needed to do lots
34  * of rangechecks, but with the filename and line number something other
35  * than Curr_filename, and yylineno, so the l_rangecheck function was
36  * created, and rangecheck just calls that. There isn't an l_frangecheck
37  * to go with frangecheck, because nothing needed it. Another case where
38  * C++ would have been nice, so we could default added arguments....
39  */
40
41 int
42 rangecheck(n, min, max, name)
43
44 int n;          /* the number to check */
45 int min;        /* has to be at least this big */
46 int max;        /* can be no bigger than this */
47 char *name;     /* describes what n represents, to use in error message */
48
49 {
50         return(l_rangecheck(n, min, max, name, Curr_filename, yylineno));
51 }
52
53 int
54 l_rangecheck(n, min, max, name, fname, lineno)
55
56 int n;          /* the number to check */
57 int min;        /* has to be at least this big */
58 int max;        /* can be no bigger than this */
59 char *name;     /* describes what n represents, to use in error message */
60 char *fname;    /* file name */
61 int lineno;     /* line number */
62
63 {
64         if ( (n < min) || (n > max) ) {
65                 l_yyerror(fname, lineno,
66                                 "%s (%d) is out of range (must be between %d and %d)",
67                                 name, n, min, max);
68                 return(NO);
69         }
70         return(YES);
71 }
72
73
74 /* This function is rather like rangecheck, except it also allows a special
75  * "empty" value. */
76
77 int
78 erangecheck(n, min, max, empty_value, name)
79
80 int n;          /* the number to check */
81 int min;        /* has to be at least this big */
82 int max;        /* can be no bigger than this */
83 int empty_value;        /* this is also a legal value */
84 char *name;     /* describes what n represents, to use in error message */
85
86 {
87         if (n == empty_value) {
88                 /* value is okay--means user set to empty */
89                 return(YES);
90         }
91         if ( (n < min) || (n > max) ) {
92                 l_yyerror(Curr_filename, yylineno,
93                                 "%s (%d) out of range (must be between %d to %d or set to nothing at all)",
94                                 name, n, min, max);
95                 return(NO);
96         }
97         return(YES);
98 }
99 \f
100
101 /* just like rangecheck except for a float instead of int */
102
103 int
104 frangecheck(n, min, max, name)
105
106 float n;        /* the number to check */
107 float min;      /* has to be at least this big */
108 float max;      /* can be no bigger than this */
109 char *name;     /* describes what n represents, to use in error message */
110
111 {
112         if ( (n < min) || (n > max) ) {
113                 l_yyerror(Curr_filename, yylineno,
114                                 "%s (%.3f) is out of range (must be between %.3f and %.3f)",
115                                 name, n, min, max);
116                 return(NO);
117         }
118         return(YES);
119 }
120 \f
121
122 /* give error and return NO if given number is not a power of 2 */
123
124 int
125 power_of2check(n, name)
126
127 int n;          /* number to verify */
128 char *name;     /* what n represents, for error message */
129
130 {
131         if ( (n <= 0) || ((n & (n - 1)) != 0)) {
132                 l_yyerror(Curr_filename, yylineno,
133                                 "%s (%d) not a power of 2", name, n);
134                 return(NO);
135         }
136         return(YES);
137 }
138 \f
139
140 /* check that current action is valid in current context. */
141 /* If so, return YES, otherwise print message and return NO */
142
143 int
144 contextcheck(validcontext, action)
145
146 int validcontext;       /* bitmap of valid contexts */
147 char *action;           /* what action is to be done, for error messages */
148
149 {
150         static int shouldBmusic; /* count of how many consecutive times
151                                 * we were called when we should have been
152                                 * in music context, but weren't
153                                 */
154
155         /* Forgetting to say 'music' can cause tons of errors,
156          * which may confuse the user. So try to deduce what they meant.
157          */
158         if (validcontext == C_MUSIC) {
159                 if (Context != C_MUSIC) {
160                         if (++shouldBmusic > 5) {
161                                 
162                                 l_yyerror(Curr_filename, yylineno, "guessing you forgot to specify 'music'; changing to music context to try to recover");
163                                 Context = C_MUSIC;
164                         }
165                 }
166                 else {
167                         shouldBmusic = 0;
168                 }
169         }
170         else {
171                 shouldBmusic = 0;
172         }
173
174         if ((validcontext & Context) == 0) {
175                 l_yyerror(Curr_filename, yylineno, "%s not valid in %s context",
176                         action, contextname(Context));
177                 return(NO);
178         }
179         return(YES);
180 }
181 \f
182
183 /* convert context number back to name */
184
185 char *
186 contextname(cont)
187
188 int cont;       /* context number */
189
190 {
191         switch(cont)  {
192         case C_MUSIC:
193                 return("music");
194         case C_SCORE:
195                 return("score");
196         case C_STAFF:
197                 return("staff");
198         case C_VOICE:
199                 return("voice");
200         case C_HEADER:
201                 return("header");
202         case C_FOOTER:
203                 return("footer");
204         case C_HEAD2:
205                 return("header2");
206         case C_FOOT2:
207                 return("footer2");
208         case C_TOP:
209                 return("top");
210         case C_TOP2:
211                 return("top2");
212         case C_BOT:
213                 return("bottom");
214         case C_BOT2:
215                 return("bottom2");
216         case C_BLOCK:
217                 return("block");
218         default:
219                 return("unknown");
220         }
221 }
222 \f
223
224 /* check that at least one staff is visible, print error message if not */
225
226 void
227 check_at_least1visible()
228
229 {
230         int staffno;
231
232         /* go through list of staffs, if we find a visible one, fine */
233         for (staffno = Score.staffs; staffno > 0; staffno--) {
234                 if ( (svpath(staffno, VISIBLE))->visible == YES) {
235                         return;
236                 }
237         }
238
239         yyerror("no staffs visible");
240         return;
241 }
242 \f
243
244 /* if there is a change in visibility status, need to have a scorefeed after
245  * that. So go through main list. If there is a change in visibility, or
246  * in number of staffs, or stafflines, or staffscale, go
247  * backwards in list till hit FEED, BAR, or beginning of list. If hit FEED
248  * first, throw it away. Then search forward from the SSV until we hit
249  * FEED or STAFF.  If FEED, fine. If STAFF, insert
250  * a FEED. If we discarded the user FEED because it was in the wrong place,
251  * mark the pagefeed field as they had it.
252  * This function also adds a measure of space to the beginning of the song
253  * if we are doing MIDI. If a song begins with a grace note,
254  * we want to move that back into the "previous" measure, so this will
255  * create that measure. It's easier to deal with that here, before
256  * makechords() is called, than to try to add it in later.
257  */
258
259 void
260 chk_vis_feed()
261
262 {
263         struct MAINLL *mll_p, *m_p;     /* to walk through main list */
264         struct MAINLL *new_feed_p;
265         short set_pagefeed = NO;        /* if to set pagefeed field */
266         short s;                        /* staff index */
267         short vis[MAXSTAFFS + 1];       /* which staffs are currently visible */
268         short stlines[MAXSTAFFS + 1];   /* stafflines for each staff */
269         float stscale[MAXSTAFFS + 1];   /* staffscale for each staff */
270         short num_staffs;               /* number of staffs */
271         short add_extra;                /* if to add extra space measure */
272
273
274         debug(4, "chk_vis_feed");
275
276         /* If doing MIDI, we want to add an extra space measure to the
277          * beginning */
278         add_extra = Doing_MIDI;
279
280         /* go through main list looking for visibility changes */
281         initstructs();
282         for (mll_p = Mainllhc_p; mll_p != (struct MAINLL *) 0;
283                                                 mll_p = mll_p->next) {
284
285                 if (mll_p->str == S_SSV) {
286                         /* SSV can only follow a BAR or BLOCKHEAD or another
287                          * SSV. If it follows a LINE/CURVE/PRHEAD,
288                          * then user must have entered music context,
289                          * but not entered any music,
290                          * just line/curve/print things. This violates our
291                          * mainlist rules, so we have to disallow */
292                         if (mll_p->prev != 0 && mll_p->prev->str != S_BAR &&
293                                         mll_p->prev->str != S_BLOCKHEAD &&
294                                         mll_p->prev->str != S_SSV) {
295                                 l_yyerror(mll_p->inputfile, mll_p->inputlineno,
296                                         "music context containing only lines/curves/print statements is not allowed");
297                         }
298
299                         /* Only want to insert a FEED if there truly was
300                          * a change in the number of staffs to be printed.
301                          * User may have set visible when it was already set,
302                          * or just changed voice visibility which didn't
303                          * cause the visibily of staffs to change, or
304                          * something like that, which doesn't count.
305                          * So see what visiblity, stafflines,
306                          * and staffscale are set to now,
307                          * then assign the SSV and see if things changed.
308                          */
309                         for (s = 1; s <= MAXSTAFFS; s++) {
310                                 /* save current values of interest */
311                                 vis[s] = svpath(s, VISIBLE)->visible;
312                                 stlines[s] = svpath(s, STAFFLINES)->stafflines;
313                                 stscale[s] = svpath(s, STAFFSCALE)->staffscale;
314                         }
315                         num_staffs = Score.staffs;
316
317                         /* make any updates */
318                         asgnssv(mll_p->u.ssv_p);
319
320                         /* now compare with previous values */
321                         for (s = 1; s <= MAXSTAFFS; s++) {
322                                 if (vis[s] != svpath(s, VISIBLE)->visible ||
323                                                 stlines[s] != svpath(s,
324                                                 STAFFLINES)->stafflines ||
325                                                 stscale[s] != svpath(s,
326                                                 STAFFSCALE)->staffscale) {
327                                         /* something changed */
328                                         break;
329                                 }
330                         }
331
332                         if (s <= MAXSTAFFS || Score.staffs != num_staffs) {
333
334                                 /* found a change. Go backwards. If find a
335                                  * FEED, discard it. Otherwise ok */
336                                 for (m_p = mll_p->prev;
337                                                 m_p != (struct MAINLL *) 0;
338                                                 m_p = m_p->prev) {
339
340                                         if (IS_CLEFSIG_FEED(m_p)) {
341                                                 /* feed in wrong place. Discard
342                                                  * this one. We'll put one in
343                                                  * the proper place later */
344                                                 set_pagefeed =
345                                                         m_p->u.feed_p->pagefeed;
346                                                 unlinkMAINLL(m_p);
347                                                 FREE(m_p);
348                                                 break;
349                                         }
350
351                                         else if (m_p->str == S_BAR) {
352                                                 break;
353                                         }
354                                 }
355
356                                 /* now look forwards. If find FEED, fine.
357                                  * If not, insert one */
358                                 for (m_p = mll_p->next;
359                                                 m_p != (struct MAINLL *) 0;
360                                                 m_p = m_p->next) {
361
362                                         if (m_p->str == S_FEED) {
363                                                 /* user already put one in */
364                                                 break;
365                                         }
366
367                                         else if (m_p->str == S_STAFF) {
368                                                 /* user neglected to put in an
369                                                  * explicit feed, so we add
370                                                  * one for them */
371                                                 new_feed_p =
372                                                         newMAINLLstruct(S_FEED,
373                                                         -1);
374                                                 new_feed_p->u.feed_p->pagefeed
375                                                                 = set_pagefeed;
376                                                 insertMAINLL(new_feed_p,
377                                                                 m_p->prev);
378                                                 break;
379                                         }
380                                 }
381                                 set_pagefeed = NO;
382                         }
383                 }
384
385                 else if (add_extra == YES && mll_p->str == S_STAFF) {
386                         /* For MIDI purposes, add a measure space to the
387                          * beginning of the song, in case we need to move
388                          * grace notes back into it. Strictly speaking,
389                          * we probably don't need to do this unless there
390                          * truly is a grace note at the beginning, but
391                          * it should never hurt to add it, and it doesn't
392                          * seem worth the effort to check. */
393                         add_pre_meas(mll_p->prev, 1, Score.staffs, YES);
394
395                         add_extra = NO;
396                 }
397         }
398 }
399 \f
400
401 /* For MIDI, we add a measure of space preceeding what the user put in.
402  * This is used in case they start the piece with grace notes that we need
403  * to move back in the preceeding measure, since this guarantees there will
404  * be a preceeding measure. Also, for when taking a "slice" of the piece,
405  * skipping measures at the beginning, this is where we attach any MIDI
406  * STUFFs that happened during the skipped part.
407  * Returns the last MAINLL added.
408  */
409
410 static struct MAINLL *
411 add_pre_meas(insert_p, start, end, add_bar)
412
413 struct MAINLL *insert_p;        /* insert after here */
414 int start;                      /* staff number of first STAFF to create */
415 int end;                        /* staff number of last STAFF to create */
416 int add_bar;                    /* if YES, add an invisible bar too */
417
418 {
419         int staff;              /* loop through staffs to be created */
420         struct MAINLL *new_p;   /* new STAFFs */
421         int numvoices;          /* number of voices on current staff */
422         int v;                  /* voice index */
423
424         /* Create a staff with measure space for all
425          * defined staffs/voices, and link onto main list */
426         for (staff = start; staff <= end; staff++) {
427
428                 /* create the STAFF struct itself */
429                 new_p = newMAINLLstruct(S_STAFF, -1);
430                 new_p->u.staff_p->staffno = staff;
431                 new_p->u.staff_p->visible = svpath(staff, VISIBLE)->visible;
432
433                 numvoices = vscheme_voices(svpath(staff, VSCHEME)->vscheme);
434                 for (v = 0; v < numvoices; v++) {
435                         add_meas_space( &(new_p->u.staff_p->groups_p[v]),
436                                                 staff, v + 1);
437                 }
438
439                 /* link onto main list, and arrange to
440                  * link the next thing after this one */
441                 insertMAINLL(new_p, insert_p);
442                 insert_p = new_p;
443         }
444         if (add_bar == YES) {
445                 /* add an invisible bar line */
446                 new_p = newMAINLLstruct(S_BAR, -1);
447                 new_p->u.bar_p->bartype = INVISBAR;
448                 insertMAINLL(new_p, insert_p);
449                 insert_p = new_p;
450         }
451         return(insert_p);
452 }
453 \f
454
455 /* check for valid interval. Unison, octave, fourths and fifths can not be
456  * major or minor. The others cannot be perfect. */
457
458 void
459 chk_interval(inttype, intnum)
460
461 int inttype;    /* PERFECT, MINOR, etc */
462 int intnum;     /* e.g., 4 for fourth */
463
464 {
465         if (intnum <= 0) {
466                 yyerror("transposition interval must be > 0");
467                 return;
468         }
469
470         /* collapse into 1 octave. It's okay that a 7th will come out zero
471          * because of the way things are checked below. */
472         intnum %= 7;
473
474         switch (inttype) {
475
476         case  PERFECT:
477                 switch (intnum) {
478                 case 1: 
479                 case 4:
480                 case 5:
481                         break;
482                 default:
483                         yyerror("specified interval cannot be perfect");
484                         break;
485                 }
486                 break;
487
488         case MAJOR:
489         case MINOR:
490                 switch(intnum) {
491                 case 1:
492                 case 4:
493                 case 5:
494                         yyerror("specified interval cannot be major or minor");
495                         break;
496                 default:
497                         break;
498                 }
499                 break;
500
501         default:
502                 /* everything else is okay */
503                 break;
504         }
505 }
506 \f
507
508 /* if specified used[] field is set to YES, print warning that its value is
509  * being overridden. This is to let user know they set the same parameter
510  * twice in the same SSV context */
511
512 void
513 used_check(mll_p, var, name)
514
515 struct MAINLL *mll_p;   /* check used[] in the SSV pointed to by this */
516 int var;                /* check this index in the used[] array */
517 char *name;             /* name of variable, for warning message */
518
519 {
520         if (mll_p == (struct MAINLL *) 0) {
521                 l_yyerror(Curr_filename, yylineno,
522                         "can't set %s in %s context", name, contextname(Context));
523                 return;
524         }
525
526         if (mll_p->str != S_SSV) {
527                 pfatal("bad argument passed to used_check()");
528         }
529
530         if (mll_p->u.ssv_p->used[var] == YES) {
531                 l_warning(Curr_filename, yylineno,
532                         "setting of '%s' parameter overrides previous setting",
533                         name);
534         }
535 }
536 \f
537
538 /* go through list and combine multiple consecutive rests into multi-rests */
539
540 void
541 combine_rests(c)
542
543 int c;  /* argument to -c command line option;
544          * only combine when there are at least
545          * this many rest measures in a row.
546          * Set to NORESTCOMBINE if user didn't use -c option. */
547
548 {
549         struct MAINLL *mll_p;   /* walk through main list */
550         struct MAINLL *begin_p = (struct MAINLL *) 0;   /* where section to
551                                                          * combine begins */
552         struct MAINLL *end_p = (struct MAINLL *) 0;
553         int all_rests = YES;
554         int n;                  /* how many measures minimum to combine */
555         int count = 0;          /* how many measures of all rests */
556         int begin_valid = NO;   /* if begin_p has been set. Can't just check to
557                                  * see if it is null, because null is valid */
558         struct SSV *ssv_p;
559         char *timerep;          /* current time signature representation */
560
561
562         debug(2, "combine_rests");
563
564         /* go through main list */
565         initstructs();
566         n = c;  /* init to value of -c option */
567         for (mll_p = Mainllhc_p; mll_p != (struct MAINLL *) 0;
568                                                 mll_p = mll_p->next) {
569
570                 if (Doing_MIDI == YES && mll_p == Mainllhc_p) {
571                         /* Don't want to combine the "extra" measure
572                          * we added in for MIDI, so skip it. */
573                         for (  ; mll_p != 0; mll_p = mll_p->next) {
574                                 if (mll_p->str == S_BAR) {
575                                         mll_p = mll_p->next;
576                                         break;
577                                 }
578                         }
579                         if (mll_p == 0) {
580                                 /* Must be no valid music data in the file.
581                                  * check4barline_at_end() should have already
582                                  * reported this to user, so we can just
583                                  * return silently here. */
584                                 return;
585                         }
586                 }
587
588                 /* for each STAFF that is visible, see if it is all rests */
589                 if (mll_p->str == S_STAFF) {
590                         /* remember where we are, in case this is the beginning
591                          * of section that needs to be combined */
592                         if (begin_valid == NO) {
593                                 begin_p = mll_p->prev;
594                                 begin_valid = YES;
595                         }
596
597                         /* if we have all rests so far, check this staff */
598                         if (all_rests == YES) {
599                                 if ((all_rests = check_all_rests
600                                                 (mll_p->u.staff_p, count))
601                                                 == NO) {
602                                         /* this measure was not all rests.
603                                          * Check to see if before that we
604                                          * had seen a run of
605                                          * all rests. If so, combine them */
606                                         do_combine(begin_p, end_p, count, n);
607                                 }
608                         }
609                 }
610
611                 else if (mll_p->str == S_BAR) {
612                         if (all_rests == YES) {
613                                 /* this measure was all rests, so
614                                  * bump counter */
615                                 if (mll_p->u.bar_p->bartype != INVISBAR) {
616                                         count++;
617                                 }
618                                 end_p = mll_p;
619                                 /* if not an ordinary bar, end the combining */
620                                 if ( (mll_p->u.bar_p->reh_type != REH_NONE) ||
621                                                 (mll_p->u.bar_p->endingloc
622                                                 != NOITEM &&
623                                                 mll_p->u.bar_p->endingloc
624                                                 != INITEM) ||
625                                                 ( (mll_p->u.bar_p->bartype
626                                                 != SINGLEBAR) &&
627                                                 (mll_p->u.bar_p->bartype !=
628                                                 INVISBAR) ) ) {
629                                         if (mll_p->u.bar_p->bartype == RESTART) {
630                                                 /* There is an empty "measure"
631                                                  * of space before restarts */
632                                                 count--;
633                                                 /* need to end combining at
634                                                  * the previous bar line */
635                                                 if (count >= n) {
636                                                         for (end_p = end_p->prev;
637                                                         end_p != 0 &&
638                                                         end_p->str != S_BAR;
639                                                         end_p = end_p->prev) {
640                                                                 ;
641                                                         }
642                                                 }
643                                         }
644
645                                         do_combine(begin_p, end_p, count, n);
646
647                                         /* re-initialize */
648                                         count = 0;
649                                         begin_p = (struct MAINLL *) 0;
650                                         all_rests = YES;
651                                         begin_valid = NO;
652                                 }
653                         }
654                         else {
655                                 /* re-init for next measure */
656                                 all_rests = YES;
657                                 count = 0;
658                                 begin_p = (struct MAINLL *) 0;
659                                 begin_valid = NO;
660                         }
661                 }
662
663                 else if (mll_p->str == S_SSV) {
664
665                         ssv_p = mll_p->u.ssv_p;
666
667                         /* If -c option was not used, we use the value of
668                          * the restcombine parameter. */
669                         if (c == NORESTCOMBINE &&
670                                         ssv_p->used[RESTCOMBINE] == YES) {
671                                 n = ssv_p->restcombine;
672                         }
673
674                         /* if there is a change in visibility or a relevant
675                          * change on an already-visible score,
676                          * that is grounds to end the combination */
677                         if ( ssv_p->used[VISIBLE] == YES ||
678                                         ((((mll_p->u.ssv_p->staffno == 0) ||
679                                         (svpath(mll_p->u.ssv_p->staffno,
680                                         VISIBLE))->visible == YES)) &&
681                                         (ssv_p->used[CLEF] == YES
682                                         || ssv_p->used[SHARPS] == YES
683                                         || ssv_p->used[TIME] == YES
684                                         || ssv_p->used[TRANSPOSITION] == YES
685                                         || ssv_p->used[ADDTRANSPOSITION] == YES
686                                         || ssv_p->used[VISIBLE] == YES))) {
687                                 do_combine(begin_p, end_p, count, n);
688
689                                 /* re-initialize */
690                                 count = 0;
691                                 begin_p = (struct MAINLL *) 0;
692                                 all_rests = YES;
693                                 begin_valid = NO;
694                         }
695
696                         /* keep track of visibility */
697                         asgnssv(mll_p->u.ssv_p);
698                 }
699                 else if (mll_p->str == S_FEED) {
700                         do_combine(begin_p, end_p, count, n);
701                         count = 0;
702                         begin_p = (struct MAINLL *) 0;
703                         all_rests = YES;
704                         begin_valid = NO;
705                 }
706         }
707
708         /* do final combination if any */
709         do_combine(begin_p, end_p, count, n);
710
711         /* If there were case of TS_ALWAYS with alternating time
712          * signatures, we had to save the entire time signature list for
713          * every measure in case it turned out to be a multirest.
714          * Now we can shorten down to one for those that aren't,
715          * and need to do this so later code works.
716          */
717         initstructs();
718         timerep = 0;
719         for (mll_p = Mainllhc_p; mll_p != 0; mll_p = mll_p->next) {
720                 struct MAINLL * nmll_p;
721
722                 if (mll_p->str != S_SSV) {
723                         continue;
724                 }
725                 asgnssv(mll_p->u.ssv_p);
726                 if (Score.timevis != PTS_ALWAYS) {
727                         continue;
728                 }
729
730                 /* If we need to change the current timerep,
731                  * need to do the permanent copy in the main list,
732                  * not the one current in Score, so save pointer to current
733                  * one in main list. */
734                 if (mll_p->u.ssv_p->used[TIME]) {
735                         timerep = mll_p->u.ssv_p->timerep;
736                 }
737
738                 for (nmll_p = mll_p->next; nmll_p != 0;
739                                                 nmll_p = nmll_p->next) {
740                         if (nmll_p->str == S_STAFF) {
741                                 if (nmll_p->u.staff_p->groups_p[0]->basictime >= -1) {
742                                         /* not followed by multi-rest,
743                                          * can truncate time sig */
744                                         char * t;
745                                         for (t = timerep; t != 0 && *t != 0; t++) {
746                                                 if (*t == TSR_ALTERNATING) {
747                                                         *t = TSR_END;
748                                                         break;
749                                                 }
750                                         }
751                                 }
752                                 break;
753                         }
754                 }
755         }
756 }
757 \f
758
759 /* given a STAFF, return NO if the staff is visible and has at least one
760  * voice which contains notes, or has lyrics or STUFF (except if stuff is on
761  * or before the first beat of the first measure. Otherwise return YES */
762
763 static int
764 check_all_rests(staff_p, count)
765
766 struct STAFF *staff_p;  /* which staff info to check */
767 int count;              /* how many measures of all rest so far */
768
769 {
770         int v;                  /* index through voices */
771         struct GRPSYL *gs_p;    /* walk through grpsyl list */
772         struct STUFF *stuff_p;  /* walk through stuff list */
773
774
775         /* if not visible, then okay to treat as all rests */
776         if ( (svpath(staff_p->staffno, VISIBLE))->visible == NO) {
777                 return(YES);
778         }
779
780         /* if has lyrics, consider that not rests */
781         if (staff_p->nsyllists > 0) {
782                 return(NO);
783         }
784
785         /* having STUFF is usually grounds for not being treated as all rests */
786         /***** what to do about earlier stuff that happens to spill into
787          *** this measure???????? *****/
788         if (staff_p->stuff_p != (struct STUFF *) 0) {
789                 /* special case. If this is the first measure of rests, and     
790                  * all STUFFs occur on or before beat 1 and have no til clause,
791                  * then that's okay.
792                  * This allows user to change tempo or something similar at
793                  * the beginning of a combined multirest. */
794                 if (count > 0) {
795                         /* Combining only applies to printing, not MIDI,
796                          * so MIDI STUFFs can be ignored */
797                         for (stuff_p = staff_p->stuff_p; stuff_p != 0;
798                                                 stuff_p = stuff_p->next) {
799                                 if (stuff_p->stuff_type != ST_MIDI) {
800                                         return(NO);
801                                 }
802                         }
803                         /* all the STUFFs must have been MIDI */
804                         return(YES);
805                 }
806                 for (stuff_p = staff_p->stuff_p; stuff_p != (struct STUFF *) 0;
807                                         stuff_p = stuff_p->next) {
808                         if (stuff_p->stuff_type == ST_MIDI) {
809                                 continue;
810                         }
811                         if (stuff_p->start.count > 1.0 || stuff_p->end.bars > 0
812                                         || stuff_p->end.count > 0.0) {
813                                 return(NO);
814                         }
815                 }
816         }
817
818         for (v = 0; v < MAXVOICES; v++) {
819                 for (gs_p = staff_p->groups_p[v]; gs_p != (struct GRPSYL *) 0;
820                                                         gs_p = gs_p->next) {
821                         /* if voice is invisible, treat like all rests */
822                         if (vvpath(staff_p->staffno, v + 1, VISIBLE)->visible == NO) {
823                                 continue;
824                         }
825
826                         if (gs_p->grpcont == GC_NOTES) {
827                                 return(NO);
828                         }
829
830                         else if (gs_p->is_meas == NO) {
831                                 /* We only combine mr and ms. If user entered
832                                  * one or more rests/spaces that fill the
833                                  * entire measure, we don't combine,
834                                  * because the user may have had some reason
835                                  * for explicitly specifying time values rather
836                                  * than using a measure duration. */
837                                 return(NO);
838                         }
839                         else if (gs_p->basictime < -1) {
840                                 /* already multirest! */
841                                 return(NO);
842                         }
843                 }
844         }
845         return(YES);
846 }
847 \f
848
849 /* effect the combination of several measures of rests into a multirest. */
850
851 static void
852 do_combine(begin_p, end_p, nummeas, min_combine)
853
854 struct MAINLL *begin_p; /* start combining from here */
855 struct MAINLL *end_p;   /* stop here */
856 int nummeas;            /* hom many measures are being combined */
857 int min_combine;        /* minimum number to combine, or NORESTCOMBINE */
858
859 {
860         struct MAINLL *new_p;
861         struct MAINLL *old_p;           /* first of items to discard */
862         struct GRPSYL *gs_p;            /* for multirest */
863         struct MAINLL *mll_p;           /* to find staff for transferring stuffs */
864         short s;                        /* index through staffs */
865         short numvoices;
866
867
868         if (min_combine == NORESTCOMBINE || nummeas < min_combine) {
869                 /* don't bother to combine */
870                 return;
871         }
872
873         /* discard everything in main list between the given points.
874          * It will be either STAFFs with all rests to be replaced or
875          * BARs to be discarded, or things associated with invisible staffs.
876          * I guess maybe we should free up the space rather than merely
877          * unhitching it from the list, but it hardly seems worth the bother,
878          * especially since we'd have to be careful not to delete the STUFFs
879          * on the first one in case they were needed at the end of this
880          * function.
881          */
882         if (begin_p == (struct MAINLL *) 0) {
883                 old_p = Mainllhc_p;
884                 Mainllhc_p = end_p;
885         }
886         else {
887                 old_p = begin_p->next;
888                 begin_p->next = end_p;
889         }
890         if (end_p != (struct MAINLL *) 0) {
891                 end_p->prev = begin_p;
892         }
893
894         /* add multirest to list */
895         for (s = Score.staffs; s > 0; s--) {
896                 new_p = newMAINLLstruct(S_STAFF, -1);
897                 gs_p = newGRPSYL(GS_GROUP);
898                 gs_p->grpcont = GC_REST;
899                 gs_p->basictime = -nummeas;
900                 gs_p->fulltime = Score.time;
901                 gs_p->staffno = s;
902                 gs_p->vno = 1;
903
904                 new_p->u.staff_p->groups_p[0] = gs_p;
905                 numvoices = vscheme_voices(svpath(s, VSCHEME)->vscheme);
906                 if (numvoices > 1) {
907                         add_meas_space( &(new_p->u.staff_p->groups_p[1]), s, 2);
908                         new_p->u.staff_p->groups_p[1]->basictime = -nummeas;
909                         /* if the first voice was invisible,
910                          * but the second voice is visible, need to convert
911                          * the space just created into a rest. */
912                         if (vvpath(s, 1, VISIBLE)->visible == NO &&
913                                         vvpath(s, 2, VISIBLE)->visible == YES) {
914                                 new_p->u.staff_p->groups_p[1]->grpcont = GC_REST;
915                         }
916                 }
917                 if (numvoices > 2) {
918                         add_meas_space( &(new_p->u.staff_p->groups_p[2]), s, 3);
919                         new_p->u.staff_p->groups_p[2]->basictime = -nummeas;
920                         /* if only the third voice is visible, need to convert
921                          * the space just created into a rest. */
922                         if (vvpath(s, 1, VISIBLE)->visible == NO &&
923                                         vvpath(s, 2, VISIBLE)->visible == NO &&
924                                         vvpath(s, 3, VISIBLE)->visible == YES) {
925                                 new_p->u.staff_p->groups_p[2]->grpcont = GC_REST;
926                         }
927                 }
928                 new_p->u.staff_p->staffno = s;
929                 new_p->u.staff_p->visible = svpath(s, VISIBLE)->visible;
930                 insertMAINLL(new_p, begin_p);
931
932                 /* if there were any STUFFs on or before the first beat of the
933                  * first measure, we have to transfer them to the stufflist of
934                  * the multirest. We can transfer the entire list, because if
935                  * there were any items that shouldn't be transferred, we
936                  * wouldn't have allowed the multirest combination in the
937                  * first place. */
938                 for (mll_p = old_p; mll_p != (struct MAINLL *) 0
939                                 && mll_p != end_p; mll_p = mll_p->next) {
940                         if (mll_p->str == S_STAFF
941                                         && mll_p->u.staff_p->staffno == s) {
942                                 new_p->u.staff_p->stuff_p =
943                                                 mll_p->u.staff_p->stuff_p;
944                                 break;
945                         }
946                 }
947         }
948 }
949 \f
950
951 /* translate MK_* to printable name */
952
953 char *
954 markname(mark)
955
956 int mark;       /* MK_* value */
957
958 {
959         switch(mark) {
960         case MK_MUSSYM:
961                 return("mussym");
962         case MK_OCTAVE:
963                 return("octave");
964         case MK_DYN:
965                 return("dyn");
966         case MK_OTHERTEXT:
967                 return("othertext");
968         case MK_CHORD:
969                 return("chord");
970         case MK_LYRICS:
971                 return("lyrics");
972         case MK_ENDING:
973                 return("ending");
974         case MK_REHEARSAL:
975                 return("rehearsal");
976         case MK_PEDAL:
977                 return("pedal");
978         default:
979                 pfatal("markname(): missing case");
980                 /*NOTREACHED*/
981                 return("");
982         }
983 }
984 \f
985
986 /* verify that a mark order list is valid */
987
988 void
989 chk_order(ssv_p, place)
990
991 struct SSV *ssv_p;      /* check the markorder list in here */
992 int place;              /* PL_*, which list to check */
993
994 {
995         int m, n;       /* index through MK_* */
996         int level;      /* value in markorder table */
997
998         for (m = 0; m < NUM_MARK; m++) {
999                 if (ssv_p->markorder[place][m] == 0) {
1000                         /* no level set for this mark, so skip it */
1001                         continue;
1002                 }
1003
1004                 /* some mark types cannot be equal with any other types */
1005                 switch (m) {
1006
1007                 case MK_LYRICS:
1008                 case MK_ENDING:
1009                 case MK_REHEARSAL:
1010                 case MK_PEDAL:
1011                         level = ssv_p->markorder[place][m];
1012                         for (n = 0; n < NUM_MARK; n++) {
1013                                 if (n == m) {
1014                                         continue;
1015                                 }
1016                                 if (ssv_p->markorder[place][n] == level) {
1017                                         l_yyerror(Curr_filename, yylineno,
1018                                                 "%s cannot be at same level as %s",
1019                                                 markname(m), markname(n));
1020                                 }
1021                         }
1022                         break;
1023
1024                 default:
1025                         break;
1026                 }
1027
1028                 if (valid_mark_item(m, place) == NO) {
1029                         char *placename;
1030                         switch (place) {
1031                         case PL_ABOVE:
1032                                 placename = "above";
1033                                 break;
1034                         case PL_BELOW:
1035                                 placename = "below";
1036                                 break;
1037                         case PL_BETWEEN:
1038                                 placename = "between";
1039                                 break;
1040                         default:
1041                                 pfatal("chk_order: invalid place %d", place);
1042                                 /* not reached; it just avoids bogus
1043                                  * "used before set" warning */
1044                                 placename = "";
1045                         }
1046                         l_warning(Curr_filename, yylineno,
1047                                         "%s not valid in %sorder list",
1048                                         markname(m), placename);
1049                 }
1050         }
1051 }
1052 \f
1053
1054 /* return YES if MK_* item is valid at given place, NO if not */
1055
1056 static int
1057 valid_mark_item(mark, place)
1058
1059 int mark;       /* MK_* */
1060 int place;      /* PL_* */
1061
1062 {
1063         if (mark == MK_OCTAVE && place == PL_BETWEEN) {
1064                 return(NO);
1065         }
1066         if ((mark == MK_ENDING || mark == MK_REHEARSAL)
1067                                                 && place != PL_ABOVE) {
1068                 return(NO);
1069         }
1070         if (mark == MK_PEDAL && place != PL_BELOW) {
1071                 return(NO);
1072         }
1073
1074         /* everything else is okay */
1075         return(YES);
1076 }
1077 \f
1078
1079 /*
1080  * User can specify that only a portion of the song is to be processed.
1081  * This is done via one or two numbers, the first measure to include and
1082  * the last.
1083  * Positive numbers are relative to the beginning of the song, negative
1084  * are relative to the end. So, as examples:
1085  *      1       // the whole song (default)
1086  *      1,-1    // another way to say the whole song
1087  *      5       // start at measure 5, through the end
1088  *      6,7     // only measures 6 and 7
1089  *      1,10    // measures 1 through 10
1090  *      1,-8    // skip the last 7 measures
1091  *      -12,-3  // only process from 12 measures from the end through
1092  *              // the third from the end
1093  *
1094  * When counting measures for this, invisbar bars do not count.
1095  * It is measured by the number of bars encountered in input, not in
1096  * performance: the bars are not double counted in sections
1097  * between repeat signs. 
1098  *
1099  * A value of zero is not allowed.
1100  * A positive start larger than the number of measures in the song
1101  *      is a user error.
1102  * A negative start that would result in starting before the beginning
1103  *      starts at the beginning (with a warning)
1104  * A positive end larger than the number of measures in the song goes to
1105  *      end of song (with a warning)
1106  * An end value that would result in starting before the beginning of the
1107  *      song or before the start value is a user error.
1108  *
1109  * Only one slice is supported. I.e., you can't ask for something
1110  * like measures 4-10, 17-24, and 46-80.
1111  * You can only ask for one of those ranges.
1112  * (You could get that effect by making 3 files and playing them one after
1113  * another, although there might be slight pauses in between.)
1114  *
1115  * A possible future enhancement might be
1116  * to also be able to specify by rehearsal mark.
1117  * If a rehearsal mark string is specified rather than a number,
1118  * the rehearsal mark  having that string (ASCII-ized by removing font, size,
1119  * and other special things) would be used as the marked place. In this case,
1120  * the end place would be only up to the rehearsal mark, not through the
1121  * measure that starts there.
1122  */
1123
1124 void
1125 chk_x_arg(x_arg, start_p, end_p)
1126
1127 char *x_arg;    /* arg to -x option specified by user */
1128 int *start_p;   /* start gets returned here */
1129 int *end_p;     /* end gets returned here */
1130
1131 {
1132         char *arg_p;    /* pointer to where end starts in x_arg */
1133
1134         /* set to defaults */
1135         *start_p = 1;
1136         *end_p = -1;
1137
1138         if (x_arg == 0 || *x_arg == '\0') {
1139                 /* No -x option, use whole song as normal */
1140                 return;
1141         }
1142
1143         *start_p = (int) strtol(x_arg, &arg_p, 0);
1144         if (arg_p == x_arg) {
1145                 if (Mupmate == YES) {
1146                         l_yyerror(0, -1, "Run > Set Options > Extract Measures: value must be one or two numbers.");
1147                 }
1148                 else {
1149                         l_yyerror(0, -1, "argument for %cx option must be one or two numbers", Optch);
1150                 }
1151         }
1152
1153         /* If there is a comma, get the "end" argument as well */
1154         if (*arg_p == ',') {
1155                 *end_p = (int) strtol(arg_p + 1, &arg_p, 0);
1156         }
1157
1158         /* We should be at end of string, either after first arg if there
1159          * was only one arg, or after second if there were two. */
1160         if (*arg_p != '\0') {
1161                 if (Mupmate == YES) {
1162                         l_yyerror(0, -1, "Run > Set Options > Extract Measures: value must be one or two numbers.");
1163                 }
1164                 else {
1165                         l_yyerror(0, -1, "argument for %cx option must be one or two numbers", Optch);
1166                 }
1167         }
1168 }
1169 \f
1170
1171 /* This function does the slicing to extract selected measures from the input */
1172
1173 void
1174 extract(start, end)
1175
1176 int start;      /* Start at this measure number.  A negative
1177                  * number means count from the end of the piece,
1178                  * so -3 would mean the last 3 bars. */
1179 int end;        /* Play only through this measure number.
1180                  * Negative is relative to the end of the piece. */
1181
1182 {
1183         int pickup;                             /* YES if song begins
1184                                                  * with pickup measure */
1185         int numbars;                            /* total number of bars */
1186         int bars;                               /* how many processed so far */
1187         int mrbars;                             /* how many bars of multirest */
1188         struct MAINLL *topstaff_mll_p = 0;      /* "all" MIDI STUFFS will
1189                                                  * be attached here */
1190         struct MAINLL *mll_p;                   /* loop through list */
1191         struct MAINLL *m_p;                     /* to look ahead in list */
1192         struct MAINLL *next_p;                  /* saved next */
1193         struct STUFF *nextstuff_p;              /* saved next of a STUFF */
1194         struct MAINLL *first_p;                 /* first STAFF at start */
1195         struct STUFF *stuff_p;                  /* loop through STUFF list */
1196         struct STUFF *pedal[MAXSTAFFS+1];       /* YES if pedal is down */
1197         struct STUFF *saveped[MAXSTAFFS+1];     /* YES if pedal was down                                                         * at entry to set of endings */
1198         int in_endings;                         /* YES if inside endings */
1199         int i;                                  /* index */
1200
1201
1202         pickup = has_pickup();
1203         if ( ( (pickup == YES && start == 0) || (pickup == NO && start == 1) )
1204                         && end == -1) {
1205                 /* Use whole song as normal; nothing to do here */
1206                 return;
1207         }
1208
1209         /* If song has a pickup measure, compensate for that.
1210          * This function treats the partial measure as a measure.
1211          * So if user specified 0 for start, they want to start at the pickup,
1212          * which will be effectively measure 1 here. If they specified 1,
1213          * they want to skip the pickup, which means they want to start at
1214          * what will be considered measure 2. And so forth.
1215          */
1216         if (pickup == YES) {
1217                 if (start >= 0) {
1218                         start++;
1219                 }
1220                 if (end >= 0) {
1221                         end++;
1222                 }
1223         }
1224         else {
1225                 /* It's not clear if these should be warnings or errors,
1226                  * but it seems friendlier to be just warnings.
1227                  * That way, if someone wants the beginning,
1228                  * but can't remember if the piece has a pickup or not,
1229                  * they can use 0, and it will always work,
1230                  * albeit possibly with a warning.
1231                  */
1232                 if (start == 0) {
1233                         warning("x option start of 0 is only valid if there is a pickup measure; using 1");
1234                         start = 1;
1235                 }
1236                 if (end == 0) {
1237                         warning("x option end of 0 is only valid if there is a pickup measure; using 1");
1238                         end = 1;
1239                 }
1240         }
1241
1242         /* Count total number of bars in song */
1243         for (numbars = 0, mll_p= Mainllhc_p; mll_p != 0; mll_p = mll_p->next) {
1244                 if (mll_p->str == S_BAR && mll_p->u.bar_p->bartype != INVISBAR) {
1245                         numbars++;
1246                 }
1247                 /* Multirests count as multiple bars */
1248                 else if (mll_p->str == S_STAFF
1249                                 && mll_p->u.staff_p->groups_p[0] != 0) {
1250                         if (mll_p->u.staff_p->groups_p[0]->basictime < -1) {
1251                                 numbars += -(mll_p->u.staff_p->groups_p[0]->basictime) - 1 ;
1252                         }
1253                         /* skip the rest of the STAFFs till BAR */
1254                         while (mll_p->next != 0 && mll_p->next->str == S_STAFF) {
1255                                 mll_p = mll_p->next;
1256                         }
1257                 }
1258         }
1259         if (numbars == 0) {
1260                 /* Only non-invisible bars count. If there aren't any
1261                  * identifiable measures, -x is pointless. */
1262                 ufatal("can't use -x on song with no visible bar lines");
1263         }
1264
1265         /* If user specified things relative to the end, convert
1266          * the relative-to-end negative values to relative-to-beginning
1267          * positive values.
1268          */
1269         if (start < 0) {
1270                 start = numbars + start + 1;
1271         }
1272         if (end < 0) {
1273                 end = numbars + end + 1;
1274         }
1275
1276         if (start > numbars) {
1277                 ufatal("Attempt to start beyond end of song");
1278         }
1279         if (end < start) {
1280                 ufatal("Attempt to end before start");
1281         }
1282         if (end <= 0) {
1283                 ufatal("Attempt to end before beginning of song");
1284         }
1285         if (start < 1) {
1286                 warning("attempt to start before beginning; ignoring");
1287                 start = 1;
1288         }
1289         if (end > numbars) {
1290                 warning("attempt to go past end; ignoring");
1291                 end = numbars;
1292         }
1293
1294         if (start == 1 && end == numbars) {
1295                 /* After all the conversions, we ended up with
1296                  * the entire song. Nothing more to do here. */
1297                 return;
1298         }
1299         /* compensate for bar being at end of measure */
1300         start--;
1301
1302
1303         /* First find the bar where we're going to start.
1304          * Find out if there are any notes tied into that measure
1305          * that have an accidental. If so, move the accidental
1306          * into the new starting measure.
1307          * Note: the 'mll_p != 0' checks are defensive; shouldn't happen.
1308          */
1309         initstructs();
1310         for (bars = 0, mll_p = Mainllhc_p; mll_p != 0 && bars < start;
1311                                                         mll_p = mll_p->next){
1312                 if (mll_p->str == S_SSV) {
1313                         /* need to keep things like keysig up to date */
1314                         asgnssv(mll_p->u.ssv_p);
1315                 }
1316                 else if (mll_p->str == S_BAR && mll_p->u.bar_p->bartype != INVISBAR) {
1317                         bars++;
1318                 }
1319                 else if (mll_p->str == S_STAFF
1320                                 && mll_p->u.staff_p->groups_p[0] != 0) {
1321                         if (mll_p->u.staff_p->groups_p[0]->basictime < -1) {
1322                                 bars += -(mll_p->u.staff_p->groups_p[0]->basictime) - 1 ;
1323                         }
1324                         /* skip the rest of the STAFFs till BAR */
1325                         while (mll_p->next->str == S_STAFF) {
1326                                 mll_p = mll_p->next;
1327                         }
1328                 }
1329         }
1330         first_p = 0;
1331         for (  ; mll_p != 0 && mll_p->str != S_BAR; mll_p = mll_p->next) {
1332                 if (mll_p->str == S_STAFF) {
1333                         mv_accs(mll_p);
1334                         if (first_p == 0) {
1335                                 first_p = mll_p;
1336                         }
1337                 }
1338         }
1339         /* Fix up the measure number to account for what was chopped off.
1340          * The pickup part may be a bit counter-intuitive...
1341          * It's because when there was a pickup, we've already added 1 to
1342          * "start" for that partial measure; with no pickup, we didn't.
1343          * As an example, if user specified -x2, then the measure number
1344          * at the barline at the end of the first printed measure should be 3.
1345          * "start" will have value 1 if there was no pickup,
1346          * but 2 if there was a pickup. So....
1347          *
1348          *                      start + 1 + (pickup ? 0 : 1);
1349          *                      -----------------------------
1350          *    no pickup:          1   + 1 +               1     = 3
1351          *    pickup:             2   + 1 +           0         = 3
1352          */
1353         Meas_num = mll_p->u.bar_p->mnum = start + 1 + (pickup ? 0 : 1);
1354
1355         /* Find the top visible staff on the new effective "first" measure,
1356          * We will be moving MIDI STUFFs into the special "extra"
1357          * space measure that exists for MIDI right before the first real
1358          * measure entered by the user.
1359          * The current top visible tells us which staff to use for "all" items.
1360          * We leave everything on the list up through the "extra" measure */
1361         if (Doing_MIDI) {
1362                 int staffs_needed;      /* number of staffs at new first meas */
1363                 struct MAINLL *laststaffmll_p = 0;      /* last staff of the extra meas
1364                          * added at the beginning for MIDI.
1365                          * Initialization just to avoid "used before set." */
1366
1367                 for (mll_p = Mainllhc_p; mll_p->str != S_BAR; mll_p = mll_p->next) {
1368                         if (mll_p->str == S_STAFF && svpath(
1369                                         mll_p->u.staff_p->staffno, VISIBLE)
1370                                         ->visible == YES) {
1371                                 topstaff_mll_p = mll_p;
1372                                 break;
1373                         }
1374                 }
1375
1376                 /* The number of staffs in the "extra" added measure might be
1377                  * smaller than the number of staffs on the new
1378                  * effective first measure.
1379                  */
1380                 staffs_needed = Score.staffs;
1381                 for (mll_p = Mainllhc_p; mll_p->str != S_BAR; mll_p = mll_p->next){
1382                         if (mll_p->str == S_STAFF) {
1383                                 laststaffmll_p = mll_p;
1384                         }
1385                 }
1386                 if (laststaffmll_p == 0){
1387                         pfatal("extract failed to find last staff in extra measure");
1388                 }
1389                 if (laststaffmll_p->u.staff_p->staffno < staffs_needed) {
1390                         (void) add_pre_meas(laststaffmll_p,
1391                                         laststaffmll_p->u.staff_p->staffno,
1392                                         staffs_needed, NO);
1393                 }
1394
1395                 /* We want to start discarding things after the extra measure,
1396                  * so skip past that. */
1397                 for (mll_p = Mainllhc_p; mll_p->str != S_BAR; mll_p = mll_p->next) {
1398                         ;
1399                 }
1400                 mll_p = mll_p->next;
1401         }
1402         else {
1403                 mll_p = Mainllhc_p;
1404         }
1405
1406         /* Pedal is off at the start */
1407         for (i = 1; i <= MAXSTAFFS; i++) {
1408                 pedal[i] = 0;
1409                 saveped[i] = 0;
1410         }
1411
1412         /* Now go through and discard anything irrelevant before the
1413          * start measure. We save all SSVs. If doing MIDI, we save any
1414          * MIDI directives that matter.
1415          * Everything else gets discarded.
1416          */
1417         mrbars = 0;
1418         next_p = 0;
1419         in_endings = NO;
1420         for (bars = 0; bars < start; mll_p = next_p) {
1421                 if (mll_p == 0) {
1422                         pfatal("got null mll_p when finding starting measure");
1423                 }
1424                 next_p = mll_p->next;
1425
1426                 switch (mll_p->str) {
1427
1428                 case S_BAR:
1429                         if (mll_p->u.bar_p->bartype != INVISBAR) {
1430                                 bars++;
1431                         }
1432                         if (mrbars > 0) {
1433                                 bars += mrbars - 1;
1434                                 if (bars > start || (mll_p->u.bar_p->bartype
1435                                                 == INVISBAR && bars == start)) {
1436                                         /* New first bar is or was a multirest,
1437                                          * so we need to retain this bar line.
1438                                          */
1439                                         continue;
1440                                 }
1441                         }
1442                         mrbars = 0;
1443
1444                         /* Keep track of if we're in a first ending. */
1445                         if (mll_p->u.bar_p->endingloc == STARTITEM) {
1446                                 in_endings = YES;
1447                         }
1448                         else if (mll_p->u.bar_p->endingloc == ENDITEM) {
1449                                 in_endings = NO;
1450                         }
1451                         break;
1452
1453                 case S_STAFF:
1454                         /* Keep track of current pedal state for this staff.
1455                          * If we find a C_ENDPED the pedal is up, otherwise
1456                          * it's down (because even with a bounce, at the end
1457                          * of the bounce, the pedal is down).
1458                          * Also deal with an octave marks that might spill
1459                          * over into the new first measure.
1460                          */
1461                         for (stuff_p = mll_p->u.staff_p->stuff_p; stuff_p != 0;
1462                                                 stuff_p = nextstuff_p) {
1463                                 /* In a previous implementation,
1464                                  * stuff_p->next could be invalid after call
1465                                  * to move_xoct, so we had to save it here.
1466                                  * With the current implementation, this
1467                                  * shouldn't be strictly necessary, but
1468                                  * it doesn't hurt. */
1469                                 nextstuff_p = stuff_p->next;
1470
1471                                 /* Note that the only time string should be
1472                                  * null is on pedal carried over from a
1473                                  * previous score, so that isn't really a
1474                                  * change in pedal state, so we can ignore it.
1475                                  */
1476                                 if (stuff_p->stuff_type == ST_PEDAL &&
1477                                                         stuff_p->string != 0) {
1478                                         pedal[mll_p->u.staff_p->staffno] =
1479                                                                 stuff_p;
1480                                 }
1481                                 if (stuff_p->stuff_type == ST_OCTAVE) {
1482                                         move_xoct(stuff_p, first_p,
1483                                                 mll_p->u.staff_p->staffno,
1484                                                 bars, start);
1485                                 }
1486                         }
1487
1488                         if (Doing_MIDI) {
1489                                 mv_midi_items(mll_p, topstaff_mll_p);
1490                         }
1491
1492                         /* Deal with multirest */
1493                         if (mll_p->u.staff_p->groups_p[0]->basictime < -1) {
1494                                 mrbars = -(mll_p->u.staff_p->groups_p[0]->basictime);
1495                                 if (bars + mrbars > start) {
1496                                         /* Slice starts in middle of multirest.
1497                                          * This multirest will be the new
1498                                          * first measure, but we need
1499                                          * to adjust the number of
1500                                          * measures worth of multirest to
1501                                          * account for starting in the middle
1502                                          * of it.
1503                                          */
1504                                     mll_p->u.staff_p->groups_p[0]->basictime =
1505                                                 -((bars + mrbars) - start);
1506
1507                                     /* If the end of the slice is also inside
1508                                      * this same multirest, shorten it down
1509                                      * to end there. It's slightly silly to
1510                                      * be saving only a part of a multirest,
1511                                      * but it's better to handle it than
1512                                      * to core dump...
1513                                      */
1514                                    if (bars + mrbars > end) {
1515                                         mll_p->u.staff_p->groups_p[0]->basictime
1516                                                 += (end - bars - mrbars + 2);
1517                                    }
1518
1519                                     /* If down to single measure, have to
1520                                      * convert from multirest to meas rest */
1521                                     if (mll_p->u.staff_p->groups_p[0]->basictime == -1) {
1522                                         mll_p->u.staff_p->groups_p[0]->is_meas = YES;
1523                                         mll_p->u.staff_p->groups_p[0]->basictime = 1;
1524                                         mll_p->u.staff_p->groups_p[0]->fulltime = Score.time;
1525                                     }
1526                                     continue;
1527                                 }
1528                         }
1529                         break;
1530
1531                 case S_SSV:
1532                         /* Need to keep all the SSVs. Not sure they
1533                          * really need to be assigned, but shouldn't hurt. */
1534                         asgnssv(mll_p->u.ssv_p);
1535                         continue;
1536
1537                 default:
1538                         break;
1539
1540                 }
1541
1542                 /* Get rid of this MAINLL. User wants it skipped. */
1543                 unlinkMAINLL(mll_p);
1544         }
1545
1546         /* Make sure there is a bar after where mll_p currently is.
1547          * If song consists of just a multirest, followed by
1548          * blocks, prints, lines, or curves, but no more music,
1549          * we need to force mll_p to get set to the bar at the end of
1550          * the multirest.
1551          */
1552         for (m_p = mll_p; m_p != 0 && m_p->str != S_BAR; m_p = m_p->next) {
1553                 ;
1554         }
1555         if (m_p == 0) {
1556                 /* No bar.  Force into hitting the next 'if' */
1557                 mll_p = 0;
1558         }
1559
1560         /* If start was in a multirest, mll_p could be zero,
1561          * so we have to use the beginning bar. */
1562         if (mll_p == 0) {
1563                 for (mll_p = Mainllhc_p; mll_p != 0 && mll_p->str != S_BAR;
1564                                                         mll_p = mll_p->next) {
1565                         ;
1566                 }
1567                 if (mll_p == 0) {
1568                         pfatal("-x option failed to find beginning bar correctly");
1569                 }
1570         }
1571
1572         /* Add pedal starts if necessary. Go through the new effective
1573          * first measure. For any staff that had the pedal down coming
1574          * into that measure, make sure the measure starts with a BEGPED.
1575          * Also, if there are any measure repeats, ufatal.
1576          * Trying to start at a measure repeat doesn't really make a lot of
1577          * sense, and it would be work to allow it, so don't bother.
1578          * Using mrpt is discouraged anyway.
1579          */
1580         for ( ; mll_p->str != S_BAR; mll_p = mll_p->next) {
1581                 if (mll_p->str == S_STAFF) {
1582                         int v;          /* voice index */
1583                         /* check for mrpt */
1584                         for (v = 0; v < MAXVOICES; v++) {
1585                                 if (is_mrpt(mll_p->u.staff_p->groups_p[v]) == YES) {
1586                                         l_ufatal(mll_p->inputfile, mll_p->inputlineno,
1587                                         "-x option not allowed to start at a mrpt");
1588                                 }
1589                         }
1590
1591                         addped(pedal[mll_p->u.staff_p->staffno], mll_p);
1592                 }       
1593         }
1594
1595         /* If slice starts inside an ending, we disallow that.
1596          * It turns out there a number of pathological cases,
1597          * particularly regarding pedal. If the pedal was down going into
1598          * the first ending, but up at the beginning of the slice, then
1599          * what should the pedal state be at the start of subsequent endings?
1600          * It should normally be based on the state coming into the ending,
1601          * but that no longer exists and conflicts with the new "beginning
1602          * of the ending" state. And more fundamentally, where do you go back
1603          * to when you reach the end of a non-final ending?
1604          * There's nothing there to go back to!
1605          * I suppose if someone has a really long ending and wants
1606          * just the middle of it, this restriction will be annoying,
1607          * but that shouldn't happen too often, and trying to handle this
1608          * was just getting too complicated!
1609          */
1610         if (in_endings == YES) {
1611                 ufatal("-x section not allowed to begin inside an ending");
1612         }
1613
1614         /* If the new first measure is in the middle of an ending,
1615          * patch up the endingloc. */
1616         if (mll_p->u.bar_p->endingloc == ENDITEM ||
1617                                         mll_p->u.bar_p->endingloc == INITEM) {
1618                 struct MAINLL *prevmll_p;
1619                 struct MAINLL *topstaffmll_p = 0;
1620
1621                 for (prevmll_p = mll_p->prev; prevmll_p != 0;
1622                                                 prevmll_p = prevmll_p->prev) {
1623                         if (prevmll_p->str == S_STAFF) {
1624                                 topstaffmll_p = prevmll_p;
1625                         }
1626                         else if (prevmll_p->str == S_BAR) {
1627                                 prevmll_p->u.bar_p->endingloc = STARTITEM;
1628                                 break;
1629                         }
1630                 }
1631                 if (prevmll_p == 0) {
1632                         if (topstaffmll_p == 0) {
1633                                 pfatal("unexpected null topstaffmll_p");
1634                         }
1635                         prevmll_p = add_pre_meas(
1636                                 topstaffmll_p->prev, 1, Score.staffs, YES);
1637                         prevmll_p->u.bar_p->endingloc = STARTITEM;
1638                 }
1639         }
1640
1641         /* Now chop off end if needed */
1642         if (end < numbars) {
1643                 for (  ; mll_p != 0 && (bars < end || mrbars > 0);
1644                                                         mll_p = mll_p->next) {
1645                         if (mll_p->str == S_BAR && mll_p->u.bar_p->bartype != INVISBAR) {
1646                                 bars++;
1647                                 mrbars = 0;
1648                         }
1649                         if (mll_p->str == S_STAFF &&
1650                                         mll_p->u.staff_p->groups_p[0] != 0 &&
1651                                         mll_p->u.staff_p->groups_p[0]->basictime < -1) {
1652                                 /* It's a multirest */
1653                                 mrbars = -(mll_p->u.staff_p->groups_p[0]->basictime);
1654                                 bars += mrbars - 1;
1655                                 if (bars >= end) {
1656                                         /* Slice ends inside the multirest.
1657                                          * Adjust its length. If down to a
1658                                          * single measure, convert */
1659                                         for (  ; mll_p->str == S_STAFF;
1660                                                         mll_p = mll_p->next) {
1661                                             mll_p->u.staff_p->groups_p[0]->basictime
1662                                                         += bars - end + 1;
1663                                             if (mll_p->u.staff_p->groups_p[0]->basictime == -1) {
1664                                                 mll_p->u.staff_p->groups_p[0]->is_meas = YES;
1665                                                 mll_p->u.staff_p->groups_p[0]->basictime = 1;
1666                                                 mll_p->u.staff_p->groups_p[0]->fulltime = Score.time;
1667                                             }
1668                                         }
1669                                         bars -= bars - end;
1670                                 }
1671                                 /* multi-rest has been handled; skip over
1672                                  * the rest of the staffs in this measure */
1673                                 while (mll_p->next != 0 &&
1674                                                 mll_p->next->str == S_STAFF) {
1675                                         mll_p = mll_p->next;
1676                                 }
1677                         }
1678                 }
1679                 if (mll_p != 0) {
1680                         /* If didn't get all the way to end of main list,
1681                          * chop off the rest.
1682                          * We don't bother to free the space.
1683                          */
1684                         mll_p->prev->next = 0;
1685                         Mainlltc_p = mll_p->prev;
1686                 }
1687
1688                 /* Remove ties/slurs going into the chopped-off part. */
1689                 for (mll_p = Mainlltc_p->prev; mll_p != 0; mll_p = mll_p->prev) {
1690                         if (mll_p->str == S_STAFF) {
1691                                 int v;          /* voice index */
1692                                 for (v = 0; v < MAXVOICES; v++) {
1693                                         struct GRPSYL *g_p;
1694                                         int n;          /* note index */
1695                                         if (mll_p->u.staff_p->groups_p[v] == 0) {
1696                                                 /* this voice doesn't exist */
1697                                                 continue;
1698                                         }
1699                                         /* find last group in this voice */
1700                                         for (g_p = mll_p->u.staff_p->groups_p[v];
1701                                                         g_p->next != 0;
1702                                                         g_p = g_p->next) {
1703                                                 ;
1704                                         } 
1705                                         /* only notes can have tie/slur */
1706                                         if (g_p->grpcont != GC_NOTES) {
1707                                                 continue;
1708                                         }
1709                                         g_p->tie = NO;
1710                                         for (n = 0; n < g_p->nnotes; n++) {
1711                                                 g_p->notelist[n].tie = NO;
1712                                                 if (g_p->notelist[n].nslurto > 0) {
1713                                                         g_p->notelist[n].nslurto = 0;
1714                                                         FREE(g_p->notelist[n].slurtolist);
1715                                                 }
1716                                         }
1717                                 }
1718
1719                                 if (mll_p->u.staff_p->staffno == 1) {
1720                                         /* No more staffs in the final bar */
1721                                         break;
1722                                 }
1723                         }
1724                 }
1725
1726                 /* If end is in the middle of an ending, or with a restart,
1727                  * fix that */
1728                 for (mll_p = Mainlltc_p; mll_p != 0; mll_p = mll_p->prev) {
1729                         if (mll_p->str == S_BAR) {
1730                                 if (mll_p->u.bar_p->endingloc == INITEM) {
1731                                         mll_p->u.bar_p->endingloc = ENDITEM;
1732                                 }
1733                                 else if (mll_p->u.bar_p->endingloc == STARTITEM) {
1734                                         struct MAINLL *pmll_p;
1735
1736                                         /* If there is a previous bar and it's
1737                                          * in an ending, we need to change this
1738                                          * one to an ENDITEM, else to NOITEM.
1739                                          */
1740                                         mll_p->u.bar_p->endingloc = NOITEM;
1741                                         for (pmll_p = mll_p->prev; pmll_p != 0;
1742                                                         pmll_p = pmll_p->prev) {
1743                                                 if (pmll_p->str == S_BAR) {
1744                                                         if (pmll_p->u.bar_p->endingloc == INITEM ||
1745                                                         pmll_p->u.bar_p->endingloc == STARTITEM) {
1746                                                                 mll_p->u.bar_p->endingloc = ENDITEM;
1747                                                         }
1748                                                         break;
1749                                                 }
1750                                         }
1751                                 }
1752                                 if (mll_p->u.bar_p->bartype == RESTART) {
1753                                         /* Not exactly clear what to do here.
1754                                          * Could ufatal. We'll convert to
1755                                          * an invisible bar. */
1756                                         mll_p->u.bar_p->bartype = INVISBAR;
1757                                 }
1758                                 break;
1759                         }
1760                 }
1761                 
1762                 /* Note: it shouldn't be necessary to do anything
1763                  * about location tags in chopped-off areas.
1764                  * Locvar code runs much later, so doesn't know
1765                  * about what was deleted, and that code has to be able
1766                  * to handle tags pointing to invisible things anyway
1767                  * for other reasons. Similarly, it is not necessary to
1768                  * shorten til clauses, since any that spill into the
1769                  * chopped-off part will still be handled okay, since a
1770                  * staff could be made invisible in the middle of a til
1771                  * clause, and this is a similar case.
1772                  */
1773         }
1774 }
1775 \f
1776
1777 /* When using -x option, if there is a tie across the beginning split point,
1778  * we need to check if there was an accidental on the note being tied from,
1779  * and if so, move the accidental to the new effective first measure.
1780  */
1781
1782 static void
1783 mv_accs(mll_p)
1784
1785 struct MAINLL *mll_p;
1786
1787 {
1788         int v;                  /* voice index */
1789         int n;                  /* note index */
1790         int staffno;
1791         int ea;                 /* effective accidental */
1792         struct GRPSYL *gs_p;
1793         struct NOTE *note_p;
1794
1795         staffno = mll_p->u.staff_p->staffno;
1796         for (v = 0; v < MAXVOICES; v++) {
1797                 if ((gs_p = mll_p->u.staff_p->groups_p[v]) == 0) {
1798                         /* voice doesn't exist on this staff */
1799                         continue;
1800                 }
1801                 /* Only non-grace note groups can be tied to */
1802                 if (gs_p->grpcont == GC_NOTES && gs_p->grpvalue != GV_ZERO) {
1803                         /* check all notes for being tied to */
1804                         for (n = 0; n < gs_p->nnotes; n++) {
1805                                 note_p = &(gs_p->notelist[n]);
1806                                 /* Only need to check if doesn't already
1807                                  * have an accidental. If effective accidental
1808                                  * differs from what note would get from        
1809                                  * key sig, need to add explicit accidental. */
1810                                 if (note_p->accidental == '\0') {
1811                                         ea = eff_acc(gs_p, note_p, mll_p);
1812                                         if (ea != acc_from_keysig(
1813                                           note_p->letter, staffno, mll_p)) {
1814                                                 note_p->accidental
1815                                                         = Acclets[ea+2];
1816                                         }
1817                                 }
1818                         }
1819                 }
1820         }
1821 }
1822 \f
1823
1824 /* If there is an octave mark whose til clause goes into the new
1825  * effective first measure due to -x option, we need to move that octave mark
1826  * to that new first measure, with its til clause appropriately shortened.
1827  */
1828
1829 static void
1830 move_xoct(stuff_p, newfirst_p, staffno, bars, start)
1831
1832 struct STUFF *stuff_p;          /* the STUFF to potentially move */
1833 struct MAINLL *newfirst_p;      /* points to first STAFF in new first meas */
1834 int staffno;                    /* which STAFF this STUFF is for */
1835 int bars;                       /* how many bars into song the STUFF is */
1836 int start;                      /* start bar number from -x option */
1837
1838 {
1839         struct STAFF *staff_p;  /* where to move the STUFF */
1840         struct MAINLL *mll_p;   /* to search for proper STAFF */
1841         struct STUFF *newstuff_p;       /* moved STUFF */
1842
1843
1844         /* See if this STUFF is an octave that spills into new first measure */
1845         if (stuff_p->stuff_type == ST_OCTAVE &&
1846                                         bars + stuff_p->end.bars >= start) {
1847                 /* Make a new STUFF, adjusting length of til clause
1848                  * to compensate for -x, and starting at count 1 */
1849                 newstuff_p = newSTUFF(stuff_p->string,
1850                                         stuff_p->dist,
1851                                         stuff_p->dist_usage,
1852                                         1.0, 0.0, 0,
1853                                         bars + stuff_p->end.bars - start,
1854                                         stuff_p->end.count,
1855                                         ST_OCTAVE,
1856                                         stuff_p->modifier,
1857                                         stuff_p->place,
1858                                         stuff_p->inputfile,
1859                                         stuff_p->inputlineno);
1860
1861                 /* Find corresponding STAFF in new first measure */
1862                 staff_p = 0;
1863                 for (mll_p = newfirst_p; mll_p != 0 && mll_p->str == S_STAFF;
1864                                                         mll_p = mll_p->next) {
1865                         if (mll_p->u.staff_p->staffno == staffno) {
1866                                 staff_p = mll_p->u.staff_p;
1867                                 break;
1868                         }
1869                 }
1870                 if (staff_p == 0) {
1871                         /* Staff apparently doesn't exist here,
1872                          * so we can ignore the octave mark. */
1873                         return;
1874                 }
1875
1876                 /* Make the octave stuff into a 1-element stufflist,
1877                  * and call the function to merge that list with the
1878                  * existing list. */
1879                 newstuff_p->next = 0;
1880                 connect_stuff(staff_p, newstuff_p);
1881         }
1882 }
1883 \f
1884
1885 /* If the passed-in pedal_p points to a pedal stuff that indicates the
1886  * pedal state needs to be altered at the beginning of the STAFF passed in,
1887  * then do that. This is for -x, for like when the slice begins where the
1888  * pedal was held down from the previous measure, so we have to add a begped.
1889  */
1890
1891 static void
1892 addped(pedal_p, mll_p)
1893
1894 struct STUFF *pedal_p;  /* last pedal state of previous measures */
1895 struct MAINLL *mll_p;   /* points to a STAFF, to add pedal to */
1896
1897 {
1898         int s;          /* staff number */
1899         struct STUFF *stuff_p;  /* walk through stuff list */
1900         struct STUFF **prev_p_p; /* This holds the address
1901                                  * of the previous' next,
1902                                  * which is where we will need
1903                                  * to update if we need to delete
1904                                  * or insert a STUFF.
1905                                  */
1906
1907         s = mll_p->u.staff_p->staffno;
1908         if (pedal_p == 0 || pedal_p->string == 0) {
1909                 /* There is no pedal carrying over into this measure,
1910                  * so no need to add anything. */
1911                 return;
1912         }
1913
1914         /* If last pedal mark was an endped, we don't need to move one in,
1915          * because pedal is off; otherwise we do. */
1916         if (pedal_p->string[4] != C_ENDPED) {
1917
1918                 /* Need to add a pedal STUFF at count 1 if
1919                  * there isn't already one at or before there.
1920                  * See if there's already one there.
1921                  */
1922                 for (stuff_p = mll_p->u.staff_p->stuff_p,
1923                                 prev_p_p = &(mll_p->u.staff_p->stuff_p);
1924                                 stuff_p != 0;
1925                                 prev_p_p = &(stuff_p->next),
1926                                 stuff_p = stuff_p->next) {
1927                         if (stuff_p->stuff_type == ST_PEDAL &&
1928                                         stuff_p->start.count
1929                                         <= 1.0) {
1930                                 /* Already had a pedal at beginning of measure.
1931                                  * If it's an ENDPED,
1932                                  * that negates the one coming in,
1933                                  * and it ought to be removed.
1934                                  * If it's a PEDAL, need to change to a BEGPED.
1935                                  * In any case, we don't need
1936                                  * to check any more STUFFs for this STAFF.
1937                                  */
1938                                 if (stuff_p->string[4] == C_ENDPED) {
1939                                         /* delete it */
1940                                         *prev_p_p = stuff_p->next;
1941                                 }
1942                                 else if (stuff_p->string[4] == C_PEDAL) {
1943                                         stuff_p->string[4] = C_BEGPED;
1944                                 }
1945                                 break;
1946                         }
1947                 }
1948                 if (stuff_p == 0) {
1949                         /* There wasn't a pedal at the
1950                          * beginning of the new first measure,
1951                          * so we will need to add one.
1952                          */
1953                         struct STUFF *newped_p;
1954
1955                         newped_p = newSTUFF(pedal_p->string,
1956                                         pedal_p->dist,
1957                                         pedal_p->dist_usage,
1958                                         1.0, 0.0, 0, 0, 0.0,
1959                                         ST_PEDAL,
1960                                         pedal_p->modifier,
1961                                         pedal_p->place,
1962                                         pedal_p->inputfile,
1963                                         pedal_p->inputlineno);
1964                         newped_p->string[4] = C_BEGPED;
1965
1966                         /* figure out where to insert it */
1967                         for (stuff_p = mll_p->u.staff_p->stuff_p,
1968                                         prev_p_p = &(mll_p->u.staff_p->stuff_p);
1969                                         stuff_p != 0;
1970                                         prev_p_p = &(stuff_p->next),
1971                                         stuff_p = stuff_p->next) {
1972                                 if (stuff_p->place == PL_ABOVE) {
1973                                         /* not far enough yet */
1974                                         continue;
1975                                 }
1976                                 if (pedal_p->all == YES && stuff_p->all == NO){
1977                                         continue;
1978                                 }
1979                                 if (stuff_p->start.count < 1.0) {
1980                                         continue;
1981                                 }
1982                                 /* found right place */
1983                                 break;
1984                         }
1985                         if (prev_p_p == 0) {
1986                                 pfatal("failed to find place to insert pedal for -x");
1987                         }
1988
1989                         /* insert into STUFF list */
1990                         newped_p->next = *prev_p_p;
1991                         *prev_p_p = newped_p;
1992                 }
1993         }
1994 }