chiark / gitweb /
Import upstream version 5.3.
[mup] / mup / mup / check.c
CommitLineData
69695f33
MW
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
15static struct MAINLL *add_pre_meas P((struct MAINLL *insert_p, int start,
16 int end, int add_bar));
17static int check_all_rests P((struct STAFF *staff_p, int count));
18static void do_combine P((struct MAINLL *begin_p, struct MAINLL *end_p,
19 int nummeas, int min_combine));
20static int valid_mark_item P((int mark, int place));
21static void mv_accs P((struct MAINLL *mll_p));
22static void move_xoct P((struct STUFF *stuff_p, struct MAINLL *newfirst_p,
23 int staffno, int bars, int start));
24static 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
41int
42rangecheck(n, min, max, name)
43
44int n; /* the number to check */
45int min; /* has to be at least this big */
46int max; /* can be no bigger than this */
47char *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
53int
54l_rangecheck(n, min, max, name, fname, lineno)
55
56int n; /* the number to check */
57int min; /* has to be at least this big */
58int max; /* can be no bigger than this */
59char *name; /* describes what n represents, to use in error message */
60char *fname; /* file name */
61int 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
77int
78erangecheck(n, min, max, empty_value, name)
79
80int n; /* the number to check */
81int min; /* has to be at least this big */
82int max; /* can be no bigger than this */
83int empty_value; /* this is also a legal value */
84char *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
103int
104frangecheck(n, min, max, name)
105
106float n; /* the number to check */
107float min; /* has to be at least this big */
108float max; /* can be no bigger than this */
109char *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
124int
125power_of2check(n, name)
126
127int n; /* number to verify */
128char *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
143int
144contextcheck(validcontext, action)
145
146int validcontext; /* bitmap of valid contexts */
147char *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
185char *
186contextname(cont)
187
188int 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
226void
227check_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
259void
260chk_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
410static struct MAINLL *
411add_pre_meas(insert_p, start, end, add_bar)
412
413struct MAINLL *insert_p; /* insert after here */
414int start; /* staff number of first STAFF to create */
415int end; /* staff number of last STAFF to create */
416int 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
458void
459chk_interval(inttype, intnum)
460
461int inttype; /* PERFECT, MINOR, etc */
462int 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
512void
513used_check(mll_p, var, name)
514
515struct MAINLL *mll_p; /* check used[] in the SSV pointed to by this */
516int var; /* check this index in the used[] array */
517char *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
540void
541combine_rests(c)
542
543int 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
763static int
764check_all_rests(staff_p, count)
765
766struct STAFF *staff_p; /* which staff info to check */
767int 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
851static void
852do_combine(begin_p, end_p, nummeas, min_combine)
853
854struct MAINLL *begin_p; /* start combining from here */
855struct MAINLL *end_p; /* stop here */
856int nummeas; /* hom many measures are being combined */
857int 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
953char *
954markname(mark)
955
956int 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
988void
989chk_order(ssv_p, place)
990
991struct SSV *ssv_p; /* check the markorder list in here */
992int 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
1056static int
1057valid_mark_item(mark, place)
1058
1059int mark; /* MK_* */
1060int 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
1124void
1125chk_x_arg(x_arg, start_p, end_p)
1126
1127char *x_arg; /* arg to -x option specified by user */
1128int *start_p; /* start gets returned here */
1129int *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
1173void
1174extract(start, end)
1175
1176int 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. */
1179int 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
1782static void
1783mv_accs(mll_p)
1784
1785struct 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
1829static void
1830move_xoct(stuff_p, newfirst_p, staffno, bars, start)
1831
1832struct STUFF *stuff_p; /* the STUFF to potentially move */
1833struct MAINLL *newfirst_p; /* points to first STAFF in new first meas */
1834int staffno; /* which STAFF this STUFF is for */
1835int bars; /* how many bars into song the STUFF is */
1836int 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
1891static void
1892addped(pedal_p, mll_p)
1893
1894struct STUFF *pedal_p; /* last pedal state of previous measures */
1895struct 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}