chiark / gitweb /
Import upstream version 5.3.
[mup] / mup / mup / beaming.c
1
2 /* Copyright (c) 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2005 by Arkkra Enterprises */
3 /* All rights reserved */
4
5 /* functions called at parse time to deal with beaming. */
6
7
8 #include "defines.h"
9 #include "structs.h"
10 #include "globals.h"
11
12
13 static void subbeam P((struct SSV *ssv_p, RATIONAL outer_time, int obi,
14         struct GRPSYL *begin_gs_p, struct GRPSYL *end_gs_p));
15 static struct GRPSYL *verify_crossbeam P((struct GRPSYL *gs_p,
16         struct GRPSYL *other_gs_p, RATIONAL start_time, RATIONAL *end_time_p,
17         int staffno, int size));
18 static void
19 slopelencheck P((struct GRPSYL *first_p, struct GRPSYL *last_p, char *bmtype));
20
21
22 /* this function will get called whenever a group is not the start or end
23  * of a custom beam group. This will fill in the beamloc based on past
24  * history. If we were most recently in a custom beam group, we still are.
25  * If we weren't before, we aren't now either. The non-custom beaming
26  * gets done later after we have collected a whole bar in do_beaming()
27  * which is called via do_bar(). */
28
29 void
30 setbeamloc(curr_grp_p, last_grp_p)
31
32 struct GRPSYL *curr_grp_p;      /* the group we're working on */
33 struct GRPSYL *last_grp_p;      /* the last group we did */
34
35 {
36         if (curr_grp_p->grpvalue == GV_ZERO) {
37                 /* grace notes don't get handled here */
38                 curr_grp_p->beamloc = NOITEM;
39                 return;
40         }
41
42         /* if the previous group is a grace group, that doesn't count. Back
43          * up in the list to the first non-grace or beginning of list */
44         for (  ; last_grp_p != (struct GRPSYL *) 0
45                                         && last_grp_p->grpvalue == GV_ZERO;
46                                         last_grp_p = last_grp_p->prev) {
47                 ;
48         }
49
50         if (last_grp_p != (struct GRPSYL *) 0) {
51
52                 switch (last_grp_p->beamloc) {
53
54                 case STARTITEM:
55                 case INITEM:
56                         curr_grp_p->beamto = last_grp_p->beamto;
57                         /* Make sure notes are 8th or shorter. Spaces (which
58                          * are allowed in cross-staff beams) can be longer. */
59                         if (curr_grp_p->basictime < 8) {
60                                 /* At this point, spaces are still
61                                  * pseudo-pitches, so have to figure out
62                                  * if this group is really notes */
63                                 int letter;     /* pitch */
64                                 int n;          /* index through notelist */
65                                 for (n = 0; n < curr_grp_p->nnotes; n++) {
66                                         letter = curr_grp_p->notelist[n].letter;
67                                         if ((letter >= 'a' && letter <= 'g') ||
68                                                         letter == PP_NO_PITCH) {
69                                                 yyerror("beamed notes must be 8th or shorter");
70                                                 break;
71                                         }
72                                 }
73                         }
74
75                         /* if previous began beaming, we must be inside now */
76                         /* if in beam before, we still are */
77                         curr_grp_p->beamloc = INITEM;
78                         break;
79
80                 case ENDITEM:
81                 case NOITEM:
82                 default:
83                         /* if previous was ending beaming, or
84                          * we weren't inside a beam, must be no beam now */
85                         curr_grp_p->beamloc = NOITEM;
86                         break;
87                 }
88         }
89         else {
90                 /* nothing specified before, so no beam */
91                 curr_grp_p->beamloc = NOITEM;
92         }
93 }
94 \f
95
96 /* take a quick jaunt through a GRPSYL list, seeing if custom
97  * beaming was already done. If so, return YES, otherwise NO.
98  * If there are any non-grace groups with beaming info, there must
99  * have been custom beaming. Also, verify that user didn't attempt to
100  * custom beam a mixture of normal and cue size notes,
101  * or try to put illegal rests or spaces inside a beam.
102  * Spaces are only allowed in cross-staff beams, unless user explicitly
103  * says to beam across spaces. Rests are also only allowed in beams if
104  * the user explicitly states they should be. Rests and spaces cannot be on
105  * the ends, and must be eighth note or shorter.
106  * We allow beaming together chords that are stemmed to another staff
107  * only if all such instances are to the same staff--not some to staff above
108  * and others to staff below--because beaming involving 3 staffs at once is
109  * just too hard to deal with.
110  * Also check that any esbm has at least 2 notes before and after it.
111  */
112
113 int
114 has_cust_beaming(grpsyl_p)
115
116 struct GRPSYL *grpsyl_p;        /* list of GRPSYLs to check */
117
118 {
119         int has = NO;
120         int size = GS_NORMAL;
121         int numnotes = 0;       /* how many notes groups, for esbm check */
122         short stemto = CS_SAME; /* to check for mixed CS_ABOVE/CS_BELOW */
123         struct GRPSYL *start_p = 0;     /* first beamed group */
124
125         for (   ; grpsyl_p != (struct GRPSYL *) NULL;
126                                 grpsyl_p = grpsyl_p->next) {
127
128                 if ((grpsyl_p->grpvalue != GV_ZERO)
129                                 && (grpsyl_p->beamloc != NOITEM)) {
130                         /* have non-grace with beam info set */
131                         has = YES;
132
133                         /* check for size or cross-staff stem mixtures */
134                         if (grpsyl_p->beamloc == STARTITEM) {
135                                 size = grpsyl_p->grpsize;
136                                 numnotes = 0;
137                                 stemto = CS_SAME;
138                         }
139                         /* check for size mixture. But only do non-cross-staff
140                          * beams here, because it's a lot easier to do the
141                          * cross-staff beam check in chk_crossbeams() */
142                         else if (grpsyl_p->grpsize != size
143                                         && grpsyl_p->beamto == CS_SAME) {
144                                 l_yyerror(grpsyl_p->inputfile,
145                                         grpsyl_p->inputlineno,
146                                         "can't beam normal and cue notes together");
147                         }
148
149                         if (grpsyl_p->grpcont != GC_NOTES) {
150                                 if (grpsyl_p->grpcont == GC_REST) {
151                                         if (grpsyl_p->basictime < 8) {
152                                                 l_yyerror(grpsyl_p->inputfile,
153                                                         grpsyl_p->inputlineno,
154                                                         "rests inside a beam must be less than quarter note duration");
155                                         }
156                                         if (grpsyl_p->beamloc != INITEM) {
157                                                 l_yyerror(grpsyl_p->inputfile,
158                                                         grpsyl_p->inputlineno,
159                                                         "beam cannot %s with a rest",
160                                                 grpsyl_p->beamloc == STARTITEM ?
161                                                 "begin" : "end");
162                                         }
163                                 }
164                                 else if (grpsyl_p->beamto == CS_SAME) {
165                                         if (grpsyl_p->beamloc != INITEM) {
166                                                 l_yyerror(grpsyl_p->inputfile,
167                                                 grpsyl_p->inputlineno,
168                                                 "beam cannot begin or end with a space");
169                                         }
170                                         if (grpsyl_p->basictime < 8) {
171                                                 l_yyerror(grpsyl_p->inputfile,
172                                                 grpsyl_p->inputlineno,
173                                                 "spaces inside a beam must be less than quarter note duration");
174                                         }
175                                 }
176                         }
177                         else if (grpsyl_p->grpvalue != GV_ZERO) {
178                                 numnotes++;
179                         }
180
181                         if (grpsyl_p->stemto != CS_SAME) {
182                                 if (stemto != CS_SAME && grpsyl_p->stemto
183                                                                 != stemto) {
184                                         l_yyerror(grpsyl_p->inputfile,
185                                         grpsyl_p->inputlineno,
186                                         "beam cannot include chords with stems to both above and below staffs");
187                                 }
188                                 stemto = grpsyl_p->stemto;
189                         }
190
191                         if (grpsyl_p->beamloc == INITEM &&
192                                         IS_STEMLEN_KNOWN(grpsyl_p->stemlen)) {
193                                 l_yyerror(grpsyl_p->inputfile,
194                                         grpsyl_p->inputlineno,
195                                         "stem len specification not allowed inside a beam");
196                         }
197         
198                         if (grpsyl_p->beamloc == STARTITEM) {
199                                 start_p = grpsyl_p;
200                         }
201                         else if (grpsyl_p->beamloc == ENDITEM) {
202                                 if (start_p != 0) {
203                                         slopelencheck(start_p, grpsyl_p, "beam");
204                                         start_p = 0;
205                                 }
206                         }
207
208                         if (grpsyl_p->breakbeam == YES
209                                         && grpsyl_p->beamto == CS_SAME) {
210                                 if (numnotes < 2) {
211                                         l_warning(grpsyl_p->inputfile,
212                                                 grpsyl_p->inputlineno,
213                                                 "esbm must be preceeded by at least 2 beamed notes");
214                                         grpsyl_p->breakbeam = NO;
215                                 }
216                                 else {
217                                         struct GRPSYL *g_p;
218
219                                         /* Check that there are
220                                          * at least 2 following beamed notes */
221                                         numnotes = 0;
222                                         for (g_p = grpsyl_p->next; g_p != 0;
223                                                         g_p = g_p->next) {
224                                                 if (g_p->grpcont == GC_NOTES &&
225                                                     g_p->grpvalue != GV_ZERO) {
226                                                         numnotes++;
227                                                 }
228                                                 if (g_p->breakbeam == YES) {
229                                                         break;
230                                                 }
231                                                 if (g_p->beamloc == ENDITEM) {
232                                                         break;
233                                                 }
234                                         }
235                                         if (numnotes < 2) {
236                                                 l_warning(grpsyl_p->inputfile,
237                                                         grpsyl_p->inputlineno,
238                                                         "esbm must be followed by at least 2 beamed notes");
239                                                 grpsyl_p->breakbeam = NO;
240                                         }
241                                         else if (grpsyl_p->grpcont != GC_NOTES) {
242                                                 /* User really should have put
243                                                  * the esbm on the preceeding
244                                                  * NOTES group. We'll be nice
245                                                  * and move it for them.
246                                                  */
247                                                 grpsyl_p->breakbeam = NO;
248                                                 for (g_p = grpsyl_p->prev;
249                                                                 g_p->grpcont != GC_NOTES;
250                                                                 g_p = g_p->prev) {
251                                                         ;
252                                                 }
253                                                 g_p->breakbeam = YES;
254                                         }
255                                 }
256                                 numnotes = 0;
257                         }
258                 }
259         }
260
261         return(has);
262 }
263 \f
264
265 /* beam notes together according to user-specified default beaming style */
266
267 void
268 do_beaming(gs_p, grpsize, staffno, vno)
269
270 struct GRPSYL *gs_p;            /* list of GRPSYLs to do beaming on */
271 int grpsize;                    /* GS_NORMAL or GS_SMALL
272                                  * (grace are handled separately) */
273 int staffno;
274 int vno;                        /* voice number */
275
276 {
277         struct SSV *ssv_beaminfo_p;     /* ssv having relevent beam info */
278         register int n;                 /* index into beamstyle list */
279         RATIONAL styletime;             /* accumulated time to beam together */
280         RATIONAL tot_time;              /* cumulative grpsyl time */
281         struct GRPSYL *first_p;         /* first in beam group */
282         struct GRPSYL *last_p;          /* last in beam group */
283         int stop;                       /* YES if need to stop beaming */
284         int beamrests;                  /* if to include rests inside beams */
285         int beamspaces;                 /* if to include spaces inside beams */
286         short stemto = CS_SAME;         /* check for mixed CS_ABOVE/CS_BELOW */
287         short restart = NO;             /* YES if could start another beam
288                                          * with current group, even though
289                                          * it can go with previous */
290
291
292
293         debug(4, "do_beaming file=%s line=%d grpsize=%d staff=%d voice=%d",
294                 gs_p->inputfile, gs_p->inputlineno, grpsize, staffno, vno);
295
296         /* if no default beaming scheme for this voice, then nothing to do--
297          * any custom beaming would have already been done */
298         ssv_beaminfo_p = vvpath(staffno, vno, BEAMSTLIST);
299         if (ssv_beaminfo_p->nbeam == 0) {
300                 return;
301         }
302
303         /* ok. We may need to do some beaming. Go through the beamstlist and
304          * see if there are any groups to beam together */
305
306         /* initialize */
307         /* point to first non-grace group */
308         for (  ; gs_p != (struct GRPSYL *) 0 && gs_p->grpcont == GC_NOTES
309                         && gs_p->grpvalue == GV_ZERO; gs_p = gs_p->next) {
310                 ;
311         }
312
313         /* if no groups, nothing to do */
314         if (gs_p == (struct GRPSYL *) 0) {
315                 return;
316         }
317
318         beamrests = vvpath(staffno, vno, BEAMSTLIST)->beamrests;
319         beamspaces = vvpath(staffno, vno, BEAMSTLIST)->beamspaces;
320         styletime = tot_time = Zero;
321         for (n = 0; n < ssv_beaminfo_p->nbeam; n++) {
322                 styletime = radd(styletime, ssv_beaminfo_p->beamstlist[n]);
323
324                 if (GE(tot_time, styletime)) {
325                         /* we're already past this beamstyle segment */
326                         continue;
327                 }
328
329                 for (first_p = last_p = 0, stop = NO;
330                                 LT(tot_time, styletime); gs_p = gs_p->next) {
331
332                         if (gs_p == 0) {
333                                 /* Must be too few groups in measure.
334                                  * This error will already have been
335                                  * reported elsewhere.
336                                  */
337                                 return;
338                         }
339
340                         /* ignore grace */
341                         while (gs_p->grpvalue == GV_ZERO) {
342                                 gs_p = gs_p->next;
343                                 if (gs_p == 0) {
344                                         /* Must have tried to end a measure
345                                          * with grace. Already reported. */
346                                         return;
347                                 }
348                         }
349
350                         tot_time = radd(tot_time, gs_p->fulltime);
351                         if (GE(tot_time, styletime)) {
352                                 /* This group puts us at or past
353                                  * the current beamstyle segment */
354                                 stop = YES;
355                         }
356
357                         /* only 8th and shorter get beamed */
358                         if (gs_p->basictime < 8 || (gs_p->grpcont == GC_SPACE &&
359                                                 beamspaces == NO) ) {
360                                 stop = YES;
361                         }
362                         else if (gs_p->grpcont == GC_REST && beamrests == NO) {
363                                 stop = YES;
364                         }
365                         else if (gs_p->grpsize != grpsize) {
366                                 /*  Wrong size to beam on this call */
367                                 stop = YES;
368                         }
369                         else if (gs_p->stemto != CS_SAME && stemto != CS_SAME
370                                         && gs_p->stemto != stemto) {
371                                 /* We don't allow beaming across three staffs,
372                                  * so have to stop current beam, but could
373                                  * possibly beam this group with following
374                                  * groups, as long as they don't have a
375                                  * conflicting stemto */
376                                 stop = YES;
377                                 restart = YES;
378                         }
379                         else if (gs_p->grpcont == GC_NOTES && 
380                                                 LE(tot_time, styletime)) {
381                                 /* found something beam-able */
382                                 if (first_p == 0) {
383                                         first_p = gs_p;
384                                 }
385                                 last_p = gs_p;
386                         }
387                         if (gs_p->stemto != CS_SAME) {
388                                 stemto = gs_p->stemto;
389                         }
390
391                         if (stop == YES) {
392                                 if (first_p != 0 && last_p != 0
393                                                         && first_p != last_p) {
394                                         /* Disallow illegal combinations of
395                                          * slope and stem length */
396                                         slopelencheck(first_p, last_p, "beam");
397
398                                         /* If there are subbeam groupings,
399                                          * do those. */
400                                         subbeam(ssv_beaminfo_p,
401                                                 rsub(styletime, ssv_beaminfo_p->beamstlist[n]),
402                                                 n, first_p, last_p);
403
404                                         /* mark beginning of beam group */
405                                         first_p->beamloc = STARTITEM;
406
407                                         /* mark all intermediate groups,
408                                          * skipping grace */
409                                         for (first_p = first_p->next;
410                                                         first_p != last_p;
411                                                         first_p = first_p->next) {
412
413                                                 if (first_p->grpvalue
414                                                                 == GV_ZERO) {
415                                                         continue;
416                                                 }
417
418                                                 first_p->beamloc = INITEM;
419
420                                                 if (IS_STEMLEN_KNOWN(first_p->stemlen)) {
421                                                         l_yyerror(first_p->inputfile, first_p->inputlineno,
422                                                             "stem len specification not allowed inside a beam");
423                                                 }
424                                         }
425
426                                         /* mark the end of the beam group */
427                                         last_p->beamloc = ENDITEM;
428                                 }
429
430                                 /* Re-init for any more bunches to beam */
431                                 first_p = last_p = 0;
432                                 stop = NO;
433                                 stemto = CS_SAME;
434                                 if (restart == YES) {
435                                         if (gs_p->grpcont == GC_NOTES) {
436                                                 first_p = gs_p;
437                                         }
438                                         restart = NO;
439                                 }
440                         }
441                 }
442         }
443 }
444 \f
445
446 /* Once a STARTITEM and ENDITEM groups of the regular beamstyle
447  * have been identified, go through them to see if there should
448  * be subgroups. If so, mark breakbeam = YES on the last group of
449  * each subgroup.
450  */
451
452 static void
453 subbeam(ssv_p, outer_time, obi, begin_gs_p, end_gs_p)
454
455 struct SSV *ssv_p;      /* to get beamstlist and subbeamstlist */
456 RATIONAL outer_time;    /* Time in measure when outer beam begins */
457 int obi;                /* outer beam index, subscript into ssv_p->beamstlist */
458 struct GRPSYL *begin_gs_p;
459 struct GRPSYL *end_gs_p;
460
461 {
462         int sbi;        /* sub beam index, subscript of ssv_p->subbeamstlist */
463         RATIONAL subgroup_time; /* duration of items in subbeamstlist */
464         RATIONAL tot_time;      /* sum of note groups in subbeaming */
465         struct GRPSYL *gs_p;    /* walk through groups */
466         struct GRPSYL *last_notegroup_p;/* Most recent GC_NOTES GRPSYL */
467
468
469         /* Check if more than one beam subgroup
470          * makes up the outer beam grouping. */
471         if (ssv_p->nbeam == ssv_p->nsubbeam) {
472                 /* There are no sub-beam groupings anywhere in the measure */
473                 return;
474         }
475
476         /* Find the subbeamlist entry that matches with the outer beam entry */
477         subgroup_time = Zero;
478         for (sbi = 0; LT(subgroup_time, outer_time); sbi++) {
479                 subgroup_time = radd(subgroup_time, ssv_p->subbeamstlist[sbi]);
480         }
481
482         if ( EQ(ssv_p->beamstlist[obi], ssv_p->subbeamstlist[sbi]) ) {
483                 /* Outer and subbeam have the same time duration,
484                  * so there aren't any subgroups in this outer beam grouping. */
485                 return;
486         }
487
488         /* There are subgroups inside the outer beam grouping,
489          * so we may need to set one or more breakbeams. */
490         subgroup_time = ssv_p->subbeamstlist[sbi];
491
492         /* If beam starts later than the outer beamstyle item begins,
493          * (e.g., if there was a rest at the beginning of the beam time),
494          * we have to count that time as already taken up from the subbeam.
495          */
496         for (tot_time = Zero, gs_p = begin_gs_p->prev; gs_p != 0;
497                                                         gs_p = gs_p->prev) {
498                 tot_time = radd(tot_time, gs_p->fulltime);
499         }
500         tot_time = rsub(tot_time, outer_time);
501         last_notegroup_p = 0;
502         for (gs_p = begin_gs_p; gs_p != end_gs_p; gs_p = gs_p->next) {
503
504                 /* Grace notes are irrelevant */
505                 if (gs_p->grpvalue == GV_ZERO) {
506                         continue;
507                 }
508
509                 /* Remember where last note group is, in case we
510                  * need to set breakbeam on it. */
511                 if (gs_p->grpcont == GC_NOTES) {
512                         last_notegroup_p = gs_p;
513                 }
514
515                 /* Add up group time values until the total equals
516                  * or exceeds that of the subgroup. */
517                 tot_time = radd(tot_time, gs_p->fulltime);
518                 if (LT(tot_time, subgroup_time)) {
519                         /* not far enough yet */
520                         continue;
521                 }
522         
523                 /* If the value exceeds, there is a note spanning the
524                  * subgroup boundary, so just ignore the subgrouping. */
525                 if (GT(tot_time, subgroup_time)) {
526                         tot_time = rsub(tot_time, subgroup_time);
527                         subgroup_time = ssv_p->subbeamstlist[++sbi];
528                         if (gs_p->grpcont != GC_NOTES) {
529                                 last_notegroup_p = 0;
530                         }
531                 }
532
533                 else {
534                         /* A group ends right at the subbeam boundary. 
535                          * Set breakbeam on last group, if there was one. 
536                          */
537                         if (last_notegroup_p != 0) {
538                                 last_notegroup_p->breakbeam = YES;
539                         }
540
541                         /* The current subbeam is finished.
542                          * Move on to the next subbeam, if there is one. */
543                         if (++sbi < ssv_p->nsubbeam) {
544                                 subgroup_time = ssv_p->subbeamstlist[sbi];
545                                 /* Since we know the subbeam we just
546                                  * finished ended exactly
547                                  * at the subbeam boundary,
548                                  * we set to time taken up so far
549                                  * by the new subbeam to zero. 
550                                  */
551                                 tot_time = Zero;
552                                 last_notegroup_p = 0;
553                         }
554                 }
555         }
556 }
557 \f
558
559 /* alt groups must always have beamloc set, so fix them */
560
561 void
562 set_alt_beams(gs_p)
563
564 struct GRPSYL *gs_p;    /* a measure's worth of GRPSYLs for a voice */
565
566 {
567         struct GRPSYL *other_gs_p;      /* group on other end of alt pair */
568
569
570         debug(4, "set_alt_beams file=%s line=%d",
571                         gs_p->inputfile, gs_p->inputlineno);
572
573         /* walk through the list, fixing any alt groups */
574         for (   ; gs_p != (struct GRPSYL *) 0; gs_p = gs_p->next) {
575
576                 /* check if is an alt pair */
577                 if (gs_p->slash_alt < 0) {
578
579                         if (gs_p->next == (struct GRPSYL *) 0) {
580                                 /* no second group in alt, will be flagged
581                                  * elsewhere */
582                                 continue;
583                         }
584
585                         /* set the pair as a beam group */
586                         gs_p->beamloc = STARTITEM;
587                         gs_p->next->beamloc = ENDITEM;
588
589                         slopelencheck(gs_p, gs_p->next, "alt");
590
591                         /* middle phase wants to have both notes in an alt group
592                          * have their alt field set, so do that */
593                         gs_p->next->slash_alt = gs_p->slash_alt;
594
595                         /* adjust preceeding and following groups if necessary.
596                          * If was already in a beam group, split off the other
597                          * parts into their own groups or put flags on the
598                          * extras if they are down to one group */
599
600                         /* find previous normal group if any and adjust */
601                         for (other_gs_p = gs_p->prev;
602                                         other_gs_p != (struct GRPSYL *) 0;
603                                         other_gs_p = other_gs_p->prev) {
604
605                                 if (other_gs_p->grpvalue != GV_ZERO) {
606                                         if (other_gs_p->grpcont == GC_REST) {
607                                                 other_gs_p->beamloc = NOITEM;
608                                         }
609                                         else {
610                                                 break;
611                                         }
612                                 }
613                         }
614
615                         if (other_gs_p != (struct GRPSYL *) 0) {
616
617                                 switch (other_gs_p->beamloc) {
618
619                                 case INITEM:
620                                         other_gs_p->beamloc = ENDITEM;
621                                         break;
622
623                                 case STARTITEM:
624                                         other_gs_p->beamloc = NOITEM;
625                                         break;
626
627                                 default:
628                                         break;
629                                 }
630                         }
631                                         
632                         /* now do the same for the following group */
633                         for (other_gs_p = gs_p->next->next;
634                                         other_gs_p != (struct GRPSYL *) 0;
635                                         other_gs_p = other_gs_p->next) {
636
637                                 if (other_gs_p->grpvalue != GV_ZERO) {
638                                         if (other_gs_p->grpcont == GC_REST) {
639                                                 other_gs_p->beamloc = NOITEM;
640                                         }
641                                         else {
642                                                 break;
643                                         }
644                                 }
645                         }
646
647                         if (other_gs_p != (struct GRPSYL *) 0) {
648
649                                 switch (other_gs_p->beamloc) {
650
651                                 case INITEM:
652                                         other_gs_p->beamloc = STARTITEM;
653                                         break;
654
655                                 case ENDITEM:
656                                         other_gs_p->beamloc = NOITEM;
657                                         break;
658
659                                 default:
660                                         break;
661                                 }
662                         }
663
664                         /* skip over the second in the pair */
665                         gs_p = gs_p->next;
666                 }
667         }
668 }
669 \f
670
671 /* Given a list of GRPSYLs on a visible voice
672  * having "bm with staff below" do all the error checking.
673  * This list of groups has to be for the bottom visible voice
674  * for the duration of the beam.
675  * There has to be a set of groups on the top non-space visible
676  * voice of the first visible staff below,
677  * which starts a "bm with staff above" at exactly
678  * the same time value. The ebm values also have to match. At every
679  * point inside the beam, one voice must have notes and the other voice
680  * must have spaces.
681  *
682  * Have to be careful in this function,
683  * because the gs_p->staffno and gs_p->vno may not be filled in yet,
684  * so have to use the staffno from the STAFF struct, and get vno from the
685  * first gs_p, which the caller is supposed to have filled in correctly.
686  *
687  * Returns the staff number of the staff containing the matching
688  * "bm with staff above" or -1 if no such staff was found.
689  */
690
691 int
692 chk_crossbeam(gs_p, mll_p)
693
694 struct GRPSYL *gs_p;    /* first group in above voice of cross staff beam */
695 struct MAINLL *mll_p;   /* gs_p hangs off of here */
696
697 {
698         struct GRPSYL *g_p;             /* for walking through group list */
699         struct GRPSYL *other_p;         /* group on other staff */
700         struct MAINLL *assoc_mll_p;     /* other staff hangs off of here */
701         struct GRPSYL *assoc_grps_p;    /* the measure-worth of groups in
702                                          * the voice being beamed to */
703         RATIONAL start_time, end_time;  /* of the above voice */
704         RATIONAL other_start, other_end;/* time of groups on below staff */
705         int user_specified_stem_len;    /* YES or NO */
706         int size = GS_NORMAL;
707         int assoc_vno;                  /* voice number on below staff */
708         struct STAFF *staff_p;
709         int staffno;
710         int vno;
711
712
713         /* only the first gs_p is guaranteed to have the right vno at this
714          * point, so save that. */
715         vno = gs_p->vno;
716         staff_p = mll_p->u.staff_p;
717         staffno = staff_p->staffno;
718
719         /* find where in the measure the beam begins, by adding up the
720          * time values of all the groups prior to the first beamed group */
721         for (start_time = Zero, g_p = gs_p->prev; g_p != (struct GRPSYL *) 0;
722                                         g_p = g_p->prev) {
723                 start_time = radd(start_time, g_p->fulltime);
724         }
725
726         /* find how long the beam lasts. Also see if there are any small
727          * groups */
728         for (end_time = start_time, g_p = gs_p; g_p != (struct GRPSYL *) 0;
729                                         g_p = g_p->next) {
730                 /* accumulate the time */
731                 end_time = radd(end_time, g_p->fulltime);
732
733                 /* check for small groups */
734                 if (g_p->grpcont == GC_NOTES && g_p->grpsize == GS_SMALL
735                                                 && g_p->grpvalue != GV_ZERO) {
736                         size= GS_SMALL;
737                 }
738
739                 /* end of the beam? */
740                 if (g_p->beamloc == ENDITEM && g_p->grpvalue != GV_ZERO) {
741                         break;
742                 }
743         }
744         if (g_p == (struct GRPSYL *) 0) {
745                 /* maybe this should be silent, since another error message
746                  * should already be printed, but this will point out that
747                  * the problem was on a cross-staff beam */
748                 l_yyerror(gs_p->inputfile, gs_p->inputlineno,
749                                         "can't find end of cross-staff beam");
750                 return(-1);
751         }
752
753         /* Make sure this is the bottom voice of the above staff.
754          * If it's voice 2 (subscript 1) then it is for sure.
755          * Otherwise, have to make sure the second and third voices, if any,
756          * have all spaces for the duration of the cross-staff beam */
757         if (vno != 1) {
758                 /* If voice 2 is visible and not all spaces,
759                  * or if we are working on voice 1 while voice 3 is
760                  * visible and not all space, there is a problem. */
761                 if (vvpath(staffno, 2, VISIBLE)->visible == YES &&
762                                 hasspace(staff_p->groups_p[1], start_time,
763                                 end_time) == NO || (vno == 0 &&
764                                 vvpath(staffno, 3, VISIBLE)->visible == YES &&
765                                 hasspace(mll_p->u.staff_p->groups_p[2],
766                                 start_time, end_time) == NO)) {
767                         l_yyerror(gs_p->inputfile, gs_p->inputlineno,
768                                 "cross-staff beam must be from bottom voice of staff %d",
769                                 mll_p->u.staff_p->staffno);
770                         return(-1);
771                 }
772         }
773
774         /* Find the associated voice, and the associated bm group
775          * in that voice. First find the next visible staff */
776         for (assoc_mll_p = mll_p->next;   ; assoc_mll_p = assoc_mll_p->next) {
777                 if (assoc_mll_p == (struct MAINLL *) 0 ||
778                                                 assoc_mll_p->str != S_STAFF) {
779                         l_yyerror(gs_p->inputfile, gs_p->inputlineno,
780                                         "no visible staff below to beam with");
781                         return(-1);
782                 }
783
784                 if (svpath(assoc_mll_p->u.staff_p->staffno, VISIBLE)->visible
785                                                         == YES) {
786                         /* found the right staff */
787                         break;
788                 }
789         }
790
791         /* Associated voice is probably voice 1 of the below staff.
792          * But there is a slight possibility it is voice 2, or even voice 3.
793          * Skip over voices that are all spaces for the duration of the beam.
794          * Since voice 3 is the "middle" voice, we check 1, then 3, then 2.
795          */
796         if (vvpath(staffno, 1, VISIBLE)->visible == YES &&
797                         hasspace(assoc_mll_p->u.staff_p->groups_p[0],
798                         start_time, end_time) == NO) {
799                 assoc_grps_p = assoc_mll_p->u.staff_p->groups_p[0];
800                 assoc_vno = 0;
801         }
802         else if (vvpath(staffno, 3, VISIBLE)->visible == YES &&
803                         hasspace(assoc_mll_p->u.staff_p->groups_p[2],
804                         start_time, end_time) == NO) {
805                 assoc_grps_p = assoc_mll_p->u.staff_p->groups_p[2];
806                 assoc_vno = 2;
807         }
808         else if (vvpath(staffno, 2, VISIBLE)->visible == YES &&
809                         hasspace(assoc_mll_p->u.staff_p->groups_p[1],
810                         start_time, end_time) == NO) {
811                 assoc_grps_p = assoc_mll_p->u.staff_p->groups_p[1];
812                 assoc_vno = 1;
813         }
814         else {
815                 l_yyerror(gs_p->inputfile, gs_p->inputlineno,
816                                 "cross-staff beam has no notes on staff %d",
817                                 assoc_mll_p->u.staff_p->staffno);
818                 return(-1);
819         }
820
821         /* Tab staffs can't be involved in cross-staff beaming */
822         if (is_tab_staff(mll_p->u.staff_p->staffno) ||
823                         is_tab_staff(assoc_mll_p->u.staff_p->staffno)) {
824                 l_yyerror(gs_p->inputfile, gs_p->inputlineno,
825                                 "cross-staff beaming not allowed on tab staff");
826                 return(-1);
827         }
828
829         /* We don't allow the different staffs to have different staffscale
830          * values: it doesn't really make much sense to allow it, and avoids
831          * all the issues like how wide to make the beams.
832          */
833         if (svpath(mll_p->u.staff_p->staffno, STAFFSCALE)->staffscale !=
834                         svpath(assoc_mll_p->u.staff_p->staffno,
835                         STAFFSCALE)->staffscale) {
836                 l_yyerror(gs_p->inputfile, gs_p->inputlineno,
837                         "staffs involved with cross-staff beams must have identical staffscale values");
838                 /* We did find which to associate with, even though
839                  * its staffscale was wrong. */
840                 return(assoc_mll_p->u.staff_p->staffno);
841         }
842
843         /* find the group that ought to be the "bm with staff above" group, by
844          * going that far time-wise into the measure on the associated voice */
845         for (other_start = Zero, other_p = assoc_grps_p;
846                                 other_p != (struct GRPSYL *) 0;
847                                 other_p = other_p->next) {
848
849                 if (GT(other_start, start_time)) {
850                         /* too far. pretend to be at end of list so we
851                          * and fall out of loop to print the error message
852                          * for this case */
853                         other_p = (struct GRPSYL *) 0;
854                         break;
855                 }
856
857                 if (EQ(other_start, start_time)) {
858                         /* found it! */
859                         break;
860                 }
861
862                 if (other_p->grpvalue == GV_ZERO) {
863                         continue;
864                 }
865
866                 /* have to keep going. Keep track of how far we are in time */
867                 other_start = radd(other_start, other_p->fulltime);
868         }
869
870         /* skip past any grace groups */
871         while (other_p != 0 && other_p->grpvalue == GV_ZERO) {
872                 other_p = other_p->next;
873         }
874
875         /* If we didn't find a voice below, or that voice's group
876          * isn't the start of a beam with above, there is a problem.
877          * In the second case, maybe user really meant to beam with some
878          * lower voice, but that would collide, which we don't allow.
879          */
880         if (other_p == (struct GRPSYL *) 0 || other_p->beamloc != STARTITEM
881                                         || other_p->beamto != CS_ABOVE) {
882                 l_yyerror(gs_p->inputfile, gs_p->inputlineno,
883                         "'bm with staff below' has no matching 'bm with staff above' (may be missing, invisible, or on wrong voice)");
884                 return(assoc_mll_p->u.staff_p->staffno);
885         }
886
887         /* check if user specified a stem length on the first group */
888         if (IS_STEMLEN_KNOWN(gs_p->stemlen)
889                                 || IS_STEMLEN_KNOWN(other_p->stemlen)) {
890                 user_specified_stem_len = YES;
891         }
892         else {
893                 user_specified_stem_len = NO;
894         }
895
896         /* go through the two voices. For each note group, verify that
897          * the other voice has space during that time period. Do the "other"
898          * staff first, because in a previous version of this function it
899          * had to be done in that order to avoid possible null pointer
900          * dereference. Now things have changed, so that doesn't matter
901          * any more, but I don't want to change the order, to make sure I
902          * don't break something.
903          */
904         other_p = verify_crossbeam(other_p,
905                         mll_p->u.staff_p->groups_p[vno], start_time,
906                         &other_end, assoc_mll_p->u.staff_p->staffno, size);
907         gs_p = verify_crossbeam(gs_p, assoc_grps_p, start_time, &end_time,
908                         mll_p->u.staff_p->staffno, size);
909
910         /* we should be pointing to the ebm group for each staff,
911          * unless of course, something went wrong, like user didn't
912          * specify an ebm */
913         if (gs_p == (struct GRPSYL *) 0 || other_p == (struct GRPSYL *) 0) {
914                 /* maybe this should be silent, since another error message
915                  * should already be printed, but this will point out that
916                  * the problem was on a cross-staff beam */
917                 l_yyerror(assoc_grps_p->inputfile, assoc_grps_p->inputlineno,
918                         "failed to find ebm for cross-staff beam");
919                 return(assoc_mll_p->u.staff_p->staffno);
920         }
921
922         if (NE(end_time, other_end)) {
923                 l_yyerror(gs_p->inputfile, gs_p->inputlineno,
924                         "ebm not at same time in measure for both voices of cross-staff beam");
925         }
926
927         /* Disallow illegal combinations of slope and stem length */
928         slopelencheck(gs_p, other_p, "beam");
929
930         return(assoc_mll_p->u.staff_p->staffno);
931 }
932 \f
933
934 /* Given the first group of a cross-staff beam, and the beginning of the
935  * list of GRPSYLs in the associated voice (the voice beamed to), and the
936  * time into the measure where the beam starts, check each group. Verify
937  * that each GC_NOTES group has GC_SPACE in the other voice and vice-versa.
938  * Also check that all note groups are the same size, and mark the spaces
939  * as the correct size so that everything in the beam has the same size.
940  * Return a pointer to the last group in the beam (null if something goes
941  * wrong). Also, return the time into the measure of the end of the beam,
942  * via the end_time_p pointer.
943  */
944
945 static struct GRPSYL *
946 verify_crossbeam(gs_p, other_gs_p, start_time, end_time_p, staffno, size)
947
948 struct GRPSYL *gs_p;    /* first group in list to be checked */
949 struct GRPSYL *other_gs_p; /* the groups_p of the associated voice */
950 RATIONAL start_time;    /* when the beam begins */
951 RATIONAL *end_time_p;   /* time through end of beam will be returned here */
952 int staffno;
953 int size;               /* GS_NORMAL or GS_SMALL */
954
955 {
956         RATIONAL end_time;
957         int has_at_least_1_note_group = NO;
958
959
960         /* go through each group in the beam */
961         for (  ; gs_p != (struct GRPSYL *) 0; gs_p = gs_p->next) {
962
963                 /* skip over any grace groups */
964                 if (gs_p->grpvalue == GV_ZERO) {
965                         continue;
966                 }
967
968                 /* find the end time of the group, for passing to hasspace() */
969                 end_time = radd(start_time, gs_p->fulltime);
970
971                 /* if notes, other voice must have space */
972                 if (gs_p->grpcont == GC_NOTES) {
973                         if (hasspace(other_gs_p, start_time, end_time) == NO) {
974                                 l_yyerror(gs_p->inputfile, gs_p->inputlineno,
975                                         "cross-staff beam must always have notes in one voice and space in the other voice");
976                                 return (struct GRPSYL *) 0;
977                         }
978                         has_at_least_1_note_group = YES;
979                         if (gs_p->grpsize != size) {
980                                 l_yyerror(gs_p->inputfile, gs_p->inputlineno,
981                                 "can't mix normal and cue size chords in cross-staff beam");
982                         }
983                 }
984
985                 /* conversely, if space, other voice must not have space */
986                 else if (gs_p->grpcont == GC_SPACE) {
987                         struct GRPSYL *g_p;
988                         RATIONAL t;
989                         int oldcont = GC_SPACE;
990
991                         /* This is somewhat like hasspace() except that checks
992                          * that the entire duration is space. Here we need
993                          * to check if there is space at least somewhere during
994                          * the time period. If so, user error.
995                          */
996                         for (g_p = other_gs_p, t = Zero; LT(t, start_time);
997                                                         g_p = g_p->next) {
998                                 if (g_p->grpvalue == GV_ZERO) {
999                                         continue;
1000                                 }
1001                                 t = radd(t, g_p->fulltime);
1002                                 oldcont = g_p->grpcont;
1003                         }
1004                         if (GT(t, start_time) && oldcont == GC_SPACE) {
1005                                 /* group spilling into this time is space */
1006                                 l_yyerror(gs_p->inputfile, gs_p->inputlineno,
1007                                         "cross-staff beam must always have notes in one voice and space in the other voice");
1008                                 return (struct GRPSYL *) 0;
1009                         }
1010                         for (   ; g_p != 0 && LT(t, end_time); g_p = g_p->next) {
1011                                 if (g_p->grpvalue == GV_ZERO) {
1012                                         continue;
1013                                 }
1014                                 if (g_p->grpcont == GC_SPACE) {
1015                                         l_yyerror(gs_p->inputfile, gs_p->inputlineno,
1016                                                 "cross-staff beam must always have notes in one voice and space in the other voice");
1017                                         return (struct GRPSYL *) 0;
1018                                 }
1019                                 t = radd(t, g_p->fulltime);
1020                         }
1021
1022                         /* mark size of spaces. Normally space can't be cue                              * size, but in this case, it makes it easier for later
1023                          * code (in print phrase at least) if everything in the
1024                          * beam--even spaces--is marked as cue size */
1025                         gs_p->grpsize = size;
1026                 }
1027
1028                 /* esbm is not currently allowed on cross-staff beams.
1029                  * It would much more complicated than normal beams,
1030                  * because the "primary" beam might perhaps best be the top,
1031                  * the bottom, or the middle, depending on where the notes are.
1032                  * Placement and print phase would have to know about that,
1033                  * so that stems could be adjusted properly,
1034                  * and beams drawn in the right places.
1035                  */
1036                 if (gs_p->breakbeam == YES) {
1037                         l_warning(gs_p->inputfile, gs_p->inputlineno,
1038                                         "esbm is not supported on cross-staff beams; being ignored");
1039                         gs_p->breakbeam = NO;
1040                 }
1041
1042                 /* see if we reached the end of the beam */
1043                 if (gs_p->beamloc == ENDITEM) {
1044                         *end_time_p = end_time;
1045                         if (has_at_least_1_note_group == NO) {
1046                                 l_yyerror(gs_p->inputfile, gs_p->inputlineno,
1047                                         "cross-staff beam has no notes on staff %d",
1048                                         staffno);
1049                         }
1050
1051                         return(gs_p);
1052                 }
1053
1054                 /* arrange for next time through the loop, by moving the
1055                  * start_time to the next group */
1056                 start_time = end_time;
1057         }
1058
1059         /* failed to find an ebm */
1060         return (struct GRPSYL *) 0;
1061 }
1062 \f
1063
1064 /* User is not allowed to specify length on both ends of a beam along with
1065  * a slope, because they could becontradictory. */
1066
1067 static void
1068 slopelencheck(first_p, last_p, bmtype)
1069
1070 struct GRPSYL *first_p;         /* first beamed group */
1071 struct GRPSYL *last_p;          /* last beamed group */
1072 char *bmtype;                   /* "beam" or "alt" */
1073
1074 {
1075         if (IS_STEMLEN_KNOWN(first_p->stemlen) == YES &&
1076                         IS_STEMLEN_KNOWN(last_p->stemlen) == YES &&
1077                         fabs(first_p->beamslope - NOBEAMANGLE) > 0.001) {
1078                 l_yyerror(last_p->inputfile, last_p->inputlineno,
1079                         "can't specify both end stem lengths and slope for %s",
1080                         bmtype);
1081         }
1082 }