chiark / gitweb /
Debianize new mup version
[mup] / mup / mup / plutils.c
1 /* Copyright (c) 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004,
2  * 2005, 2006 by Arkkra Enterprises */
3 /* All rights reserved */
4 /*
5  * Name:        plutils.c
6  *
7  * Description: This file contains utility functions belonging to the placement
8  *              phase.  Some of them are also used by other phases.
9  */
10
11 #include "defines.h"
12 #include "structs.h"
13 #include "globals.h"
14
15 static int phrase_tieslur_note P((struct GRPSYL *gs_p, int nidx, int side,
16                 int interfere));
17 static int tied_to_nidx P((struct GRPSYL *gs_p, int nidx));
18 static int slurred_to_nidx P((struct GRPSYL *gs_p, int nidx, int sidx));
19 static RATIONAL lefttime P((double count, struct GRPSYL *firstgs_p,
20                 int timeden));
21 static RATIONAL righttime P((double count, struct GRPSYL *firstgs_p,
22                 int timeden));
23
24 /*
25  * Name:        nextnongrace()
26  *
27  * Abstract:    Return next nongrace group in a GRPSYL list.
28  *
29  * Returns:     pointer to GRPSYL of next nongrace group, 0 if none
30  *
31  * Description: This function loops down the GRPSYL linked list from the given
32  *              starting point.  It returns the next nongrace GRPSYL, or 0
33  *              if none.
34  */
35
36 struct GRPSYL *
37 nextnongrace(gs_p)
38
39 struct GRPSYL *gs_p;    /* current group */
40
41 {
42         gs_p = gs_p->next;
43         while (gs_p != 0 && gs_p->grpvalue == GV_ZERO)
44                 gs_p = gs_p->next;
45         return (gs_p);
46 }
47 \f
48 /*
49  * Name:        prevnongrace()
50  *
51  * Abstract:    Return previous nongrace group in a GRPSYL list.
52  *
53  * Returns:     pointer to GRPSYL of previous nongrace group, 0 if none
54  *
55  * Description: This function loop up the GRPSYL linked list from the given
56  *              starting point.  It returns the previous nongrace GRPSYL, or 0
57  *              if none.
58  */
59
60 struct GRPSYL *
61 prevnongrace(gs_p)
62
63 struct GRPSYL *gs_p;    /* current group */
64
65 {
66         gs_p = gs_p->prev;
67         while (gs_p != 0 && gs_p->grpvalue == GV_ZERO)
68                 gs_p = gs_p->prev;
69         return (gs_p);
70 }
71 \f
72 /*
73  * Name:        nextglobnongrace()
74  *
75  * Abstract:    Return next nongrace group in this voice.
76  *
77  * Returns:     pointer to GRPSYL of next nongrace group, 0 if none
78  *
79  * Description: This function, given a nongrace and the MLL structure it hangs
80  *              off of, returns the next nongrace in this voice, even if it's in
81  *              the next measure.  If it is in the next measure, *mll_p_p gets
82  *              updated.  But if that next measure is a second or later ending,
83  *              it's not considered to be a "next" measure, so return 0.
84  */
85
86 struct GRPSYL *
87 nextglobnongrace(gs_p, mll_p_p)
88
89 struct GRPSYL *gs_p;            /* current group */
90 struct MAINLL **mll_p_p;        /* MLL structure it is hanging off of */
91
92 {
93         do {
94                 gs_p = nextgrpsyl(gs_p, mll_p_p);
95         } while (gs_p != 0 && gs_p->grpvalue == GV_ZERO);
96         return (gs_p);
97 }
98 \f
99 /*
100  * Name:        prevglobnongrace()
101  *
102  * Abstract:    Return previous nongrace group in this voice.
103  *
104  * Returns:     pointer to GRPSYL of previous nongrace group, 0 if none
105  *
106  * Description: This function, given a nongrace and the MLL structure it hangs
107  *              off of, returns the prev nongrace in this voice, even if it's
108  *              in an earlier measure.  If we are at the start of an ending,
109  *              it skips over any previous ending and goes to the measure
110  *              preceding the first ending.  If the resulting nongrace is in a
111  *              previous measure, *mll_p_p gets updated.
112  */
113
114 struct GRPSYL *
115 prevglobnongrace(gs_p, mll_p_p)
116
117 struct GRPSYL *gs_p;            /* current group */
118 struct MAINLL **mll_p_p;        /* MLL structure it is hanging off of */
119
120 {
121         do {
122                 gs_p = prevgrpsyl(gs_p, mll_p_p);
123         } while (gs_p != 0 && gs_p->grpvalue == GV_ZERO);
124         return (gs_p);
125 }
126 \f
127 /*
128  * Name:        drmo()
129  *
130  * Abstract:    Detect rightmost one.
131  *
132  * Returns:     void
133  *
134  * Description: This function returns the bit position of the rightmost bit
135  *              that is a 1 in the given number, the low order bit being
136  *              bit 0.  The given number must not be 0.
137  */
138
139 int
140 drmo(num)
141
142 register int num;
143
144 {
145         register int n;
146
147         for (n = 0; n < 8 * sizeof(int); n++) {
148                 if ( (num & (1 << n)) != 0 )
149                         return (n);
150         }
151         pfatal("0 was passed to drmo");
152         return (0);     /* dead code, but keeps lint happy */
153 }
154 \f
155 /*
156  * Name:        tieslurpad()
157  *
158  * Abstract:    How much tie/slur padding is needed after this group?
159  *
160  * Returns:     Padding in inches.
161  *
162  * Description: This function returns the amount of padding needed after a
163  *              group due to ties or slurs, if the given group is tied to the
164  *              next group, or any note in it is tied or slurred to a note
165  *              in the following group.  Otherwise it returns zero.
166  *              NOTE:  This function ignores staffscale.
167  */
168
169 double
170 tieslurpad(staff_p, gs_p)
171
172 struct STAFF *staff_p;          /* the staff the group is connected to */
173 struct GRPSYL *gs_p;            /* the group after which padding may occur */
174
175 {
176         struct NOTE *note_p;    /* point at a note structure */
177         struct GRPSYL *gtemp_p; /* temp GRPSYL pointer */
178         struct GRPSYL *this_p;  /* first GRPSYL in this voice */
179         struct GRPSYL *that_p;  /* first GRPSYL in other voice */
180         RATIONAL starttime;     /* time into measure where *gs_p starts */
181         float pad;              /* how much padding is needed */
182         int interfere;          /* does other voice have notes/rests here? */
183         int stepdiff;           /* vertical reach of a curve */
184         int n;                  /* index into notes in group */
185         int s;                  /* index into notes slurred to */
186
187
188         /* syllables can't have ties or slurs */
189         if (gs_p->grpsyl != GS_GROUP)
190                 return (0);
191
192         /* rests and spaces can't have ties or slurs */
193         if (gs_p->grpcont != GC_NOTES)
194                 return (0);
195
196         /* if last group in measure, don't need any more space */
197         if (gs_p->next == 0)
198                 return (0);
199
200         /*
201          * Find the first group in this measure, and total time preceding the
202          * group we were given.  We need this to figure out which voice we are
203          * in, and, if there is another voice, whether it has only spaces
204          * during the time of our group, which affects how the curves should
205          * look.
206          */
207         starttime = Zero;
208         for (gtemp_p = gs_p->prev, this_p = gs_p; gtemp_p != 0;
209                         this_p = gtemp_p, gtemp_p = gtemp_p->prev)
210                 starttime = radd(starttime, gtemp_p->fulltime);
211
212         /* point at other voice, or null pointer if none */
213         if (staff_p->groups_p[0] == this_p)
214                 that_p = staff_p->groups_p[1];  /* might be 0 */
215         else if (staff_p->groups_p[1] == this_p)
216                 that_p = staff_p->groups_p[0];  /* might be 0 */
217         else
218                 that_p = 0;     /* we are voice 3, ignore other voices */
219
220         if (that_p == 0 || hasspace(that_p, starttime,
221                                 radd(starttime, gs_p->fulltime)))
222                 interfere = NO;
223         else
224                 interfere = YES;
225
226         pad = 0;                /* start with no padding */
227
228         /*
229          * Loop through every note in this group.  If it's tied, check each
230          * note to see if either it or the note it's tied to is ineligible for
231          * phrase-like curves.  If so, there will be a horizontally aligned
232          * curve, and we need to pad.  The note must be the same in both
233          * groups, so there's no need to consider vertical distances at this
234          * point.  Then loop through the 0 or more slurs from this note to
235          * note(s) in the next group.  For each one, find the vertical distance
236          * between the two notes.  The padding it needs is based on this and on
237          * whether phrase-like curves can be drawn.  Keep track of the maximum
238          * padding needed by any pair of notes.
239          * We also need to pad if the stems are UP-DOWN, because that leaves no
240          * room for the curve.
241          */
242         for (n = 0; n < gs_p->nnotes; n++) {
243                 note_p = &gs_p->notelist[n];
244                 if (note_p->tie == YES) {
245                         if (gs_p->stemdir == UP && gs_p->next->stemdir == DOWN
246                         || phrase_tieslur_note(gs_p, n, STARTITEM, interfere)
247                         == NO || phrase_tieslur_note(gs_p->next, tied_to_nidx(
248                         gs_p, n), ENDITEM, interfere) == NO)
249                                 pad = MAX(pad, TIESLURPAD);
250                 }
251                 for (s = 0; s < note_p->nslurto; s++) {
252                         /*
253                          * If it's a slur to/from nowhere, don't deal with it
254                          * here.  It is considered along with the width of the
255                          * individual note.
256                          */
257                         if (IS_NOWHERE(note_p->slurtolist[s].octave))
258                                 continue;       /* from nowhere */
259
260                         stepdiff = abs(
261                                         ( note_p->octave * 7 +
262                                         Letshift[ note_p->letter - 'a' ] ) -
263                                         ( note_p->slurtolist[s].octave * 7 +
264                                         Letshift[ note_p->slurtolist[s].letter
265                                                 - 'a' ] )
266                                         );
267                         if (gs_p->stemdir == UP && gs_p->next->stemdir == DOWN
268                         || phrase_tieslur_note(gs_p, n, STARTITEM, interfere)
269                         == NO || phrase_tieslur_note(gs_p->next,
270                         slurred_to_nidx(gs_p, n, s), ENDITEM, interfere) == NO){
271                                 pad = MAX(pad, stepdiff <= 3 ? TIESLURPAD :
272                                 TIESLURPAD + (stepdiff - 3) * STEPSIZE / 2);
273                         } else {
274                                 pad = MAX(pad, stepdiff <= 3 ? 0 :
275                                 (stepdiff - 3) * STEPSIZE / 2);
276                         }
277                 }
278         }
279
280         return (pad);           /* max padding needed by any pair of notes */
281 }
282 \f
283 /*
284  * Name:        phrase_tieslur_note()
285  *
286  * Abstract:    Is the given note the end note and eligible for "new" tie/slur?
287  *
288  * Returns:     YES or NO
289  *
290  * Description: This function determines whether a tie or slur to/from the
291  *              given note is to be drawn like a phrase mark (as opposed to
292  *              drawing it vertically aligned with the note).
293  */
294
295 static int
296 phrase_tieslur_note(gs_p, nidx, side, interfere)
297
298 struct GRPSYL *gs_p;            /* point at note's group */
299 int nidx;                       /* index to this note in notelist */
300 int side;                       /* STARTITEM (curve here to right) or ENDITEM */
301 int interfere;                  /* does the other voice have notes/rests here?*/
302
303 {
304         /* check for each bad condition, returning NO if it exists */
305
306         /* inner note of a group */
307         if (nidx != 0 && nidx != gs_p->nnotes - 1)
308                 return (NO);
309
310         /* bottom note of voice 1 and other voice interferes */
311         if (gs_p->vno == 1 && nidx == gs_p->nnotes - 1 && interfere)
312                 return (NO);
313
314         /* top note of voice 2 and other voice interferes */
315         if (gs_p->vno == 2 && nidx == 0 && interfere)
316                 return (NO);
317
318         /* antistem note if "with" list is present */
319         /*  (don't need to check normwith; if it weren't YES we would have */
320         /*  returned above) */
321         if (gs_p->nwith != 0 && gs_p->stemdir == UP && nidx == gs_p->nnotes - 1)
322                 return (NO);
323
324         /* antistem note if "with" list is present */
325         /*  (don't need to check normwith; if it weren't YES we would have */
326         /*  returned above) */
327         if (gs_p->nwith != 0 && gs_p->stemdir == DOWN && nidx == 0)
328                 return (NO);
329
330         /* stem in the way of left end of curve */
331         if (side == STARTITEM && gs_p->basictime >= 2 && gs_p->stemdir == UP &&
332                         nidx == 0 && gs_p->nnotes > 1)
333                 return (NO);
334
335         /* stem in the way of right end of curve */
336         if (side == ENDITEM && gs_p->basictime >= 2 && gs_p->stemdir == DOWN &&
337                         nidx == gs_p->nnotes - 1 && gs_p->nnotes > 1)
338                 return (NO);
339
340         return (YES);
341 }
342 \f
343 /*
344  * Name:        tied_to_nidx()
345  *
346  * Abstract:    Return the note index of the note the given note is tied to.
347  *
348  * Returns:     index into gs_p->next->notelist
349  *
350  * Description: This function is given a valid group (not the last one in the
351  *              measure) and an index into its notelist to a note that is tied
352  *              to the next group.  It returns the index into the next group's
353  *              notelist to the note that the first group's note is tied to.
354  */
355
356 static int
357 tied_to_nidx(gs_p, nidx)
358
359 struct GRPSYL *gs_p;            /* point at note's group */
360 int nidx;                       /* index to this note in notelist */
361
362 {
363         struct NOTE *nl_ptr;    /* ptr to next group's notelist */
364         int n;
365
366
367         nl_ptr = gs_p->next->notelist;
368
369         for (n = 0; n < gs_p->next->nnotes; n++) {
370                 if (gs_p->notelist[nidx].letter == nl_ptr[n].letter &&
371                     gs_p->notelist[nidx].octave == nl_ptr[n].octave)
372                         return (n);
373         }
374
375         pfatal("tied_to_nidx: can't find note tied to");
376         return (0);             /* to keep lint happy */
377 }
378 \f
379 /*
380  * Name:        slurred_to_nidx()
381  *
382  * Abstract:    Return the note index of the note the given note is slurred to.
383  *
384  * Returns:     index into gs_p->next->notelist
385  *
386  * Description: This function is given a valid group (not the last one in the
387  *              measure) and an index into its notelist to a note that is tied
388  *              to the next group.  It returns the index into the next group's
389  *              notelist to the note that the first group's note is tied to.
390  */
391
392 static int
393 slurred_to_nidx(gs_p, nidx, sidx)
394
395 struct GRPSYL *gs_p;            /* point at note's group */
396 int nidx;                       /* index to this note in notelist */
397 int sidx;                       /* index to slurred to note in slurto list */
398
399 {
400         struct NOTE *nl_ptr;    /* ptr to next group's notelist */
401         int n;
402
403
404         nl_ptr = gs_p->next->notelist;
405
406         for (n = 0; n < gs_p->next->nnotes; n++) {
407                 if (gs_p->notelist[nidx].slurtolist[sidx].letter ==
408                                         nl_ptr[n].letter &&
409                     gs_p->notelist[nidx].slurtolist[sidx].octave ==
410                                         nl_ptr[n].octave)
411                         return (n);
412         }
413
414         pfatal("slurred_to_nidx: can't find note slurred to");
415         return (0);             /* to keep lint happy */
416 }
417 \f
418 /*
419  * Name:        hasspace()
420  *
421  * Abstract:    Finds out if the given voice has space during given time.
422  *
423  * Returns:     YES or NO
424  *
425  * Description: This function is given a linked list of groups to check
426  *              during a given time interval.  If the list consists entirely
427  *              of space(s) during the time interval, the function returns
428  *              YES.  Otherwise it returns NO.  If vtime2 is greater than the
429  *              length of a measure, the extra, nonexistent time is regarded
430  *              as all spaces.  If the linked list of groups doesn't exist
431  *              (gs_p is a null pointer), the function returns YES, since
432  *              there is nothing there but "space".
433  */
434
435 int
436 hasspace(gs_p, vtime, vtime2)
437
438 register struct GRPSYL *gs_p;   /* starts pointing at the first GRPSYL list */
439 RATIONAL vtime, vtime2; /* time when to start and stop checking for space */
440
441 {
442         RATIONAL t;             /* accumulate time */
443         int oldcont;            /* content of previous group */
444
445
446         /* "no linked list exists" counts as all spaces */
447         if (gs_p == 0)
448                 return (YES);
449
450         oldcont = GC_SPACE;     /* prevent useless 'used before set' warning */
451
452         /* accumulate time until crossing vtime boundary */
453         for (t = Zero; LT(t, vtime); gs_p = gs_p->next) {
454                 if (gs_p->grpvalue == GV_ZERO)
455                         continue;
456                 t = radd(t, gs_p->fulltime);
457                 oldcont = gs_p->grpcont;
458         }
459
460         if (GT(t, vtime) && oldcont != GC_SPACE)
461                 return (NO);
462
463         for ( ; gs_p != 0 && LT(t, vtime2); gs_p = gs_p->next) {
464                 if (gs_p->grpvalue == GV_ZERO)
465                         continue;
466                 if (gs_p->grpcont != GC_SPACE)
467                         return (NO);
468                 t = radd(t, gs_p->fulltime);
469         }
470
471         return (YES);
472 }
473 \f
474 /*
475  * Name:        closestgroup()
476  *
477  * Abstract:    Find closest nongrace group in this voice to given time value.
478  *
479  * Returns:     pointer to the closest nongrace GRPSYL
480  *
481  * Description: This function finds the GRPSYL in the given linked list that is
482  *              closest, timewise, to the given count number, ignoring grace
483  *              groups.
484  */
485
486 struct GRPSYL *
487 closestgroup(count, firstgs_p, timeden)
488
489 double count;                   /* which count of the measure */
490 struct GRPSYL *firstgs_p;       /* first GRPSYL of relevant voice in measure */
491 int timeden;                    /* denominator of current time signature */
492
493 {
494         RATIONAL reqtime;       /* time requested */
495         RATIONAL tottime;       /* total time in measure so far */
496         RATIONAL otottime;      /* old total time in measure so far */
497         struct GRPSYL *gs_p;    /* point along group list */
498         struct GRPSYL *ogs_p;   /* (old) point along group list */
499
500
501         /* skip over any initial grace groups */
502         if (firstgs_p->grpvalue == GV_ZERO)
503                 firstgs_p = nextnongrace(firstgs_p);
504
505         /* if at or before the first count, it's closest to first group */
506         if (count <= 1)
507                 return (firstgs_p);
508
509         /* get requested time to nearest tiny part of a count, in lowest terms*/
510         reqtime.n = 4 * MAXBASICTIME * (count - 1) + 0.5;
511         reqtime.d = 4 * MAXBASICTIME * timeden;
512         rred(&reqtime);
513
514         /*
515          * Loop through this voice accumulating time values.  As soon as we
516          * equal or exceed the requested time value, check whether the
517          * requested time is closer to the new accumulated time, or that before
518          * this last group.  Return the closest one.
519          */
520         tottime = Zero;
521         for (ogs_p = firstgs_p, gs_p = nextnongrace(ogs_p); gs_p != 0;
522                                 ogs_p = gs_p, gs_p = nextnongrace(gs_p)) {
523                 otottime = tottime;
524                 tottime = radd(tottime, ogs_p->fulltime);
525                 if (GE(tottime, reqtime)) {
526                         if (GT( rsub(reqtime,otottime), rsub(tottime,reqtime) ))
527                                 return (gs_p);
528                         else
529                                 return (ogs_p);
530                 }
531         }
532
533         /* requested time is after last group; return last group */
534         return (ogs_p);
535 }
536 \f
537 /*
538  * Name:        chkallspace()
539  *
540  * Abstract:    Check if voice is all spaces for the voice this stuff is on.
541  *
542  * Returns:     YES or NO
543  *
544  * Description: This function checks where one voice seems to be all spaces
545  *              during the duration of a phrase mark, or other stuff which must
546  *              be associated with a definite group.  The tricky thing is that
547  *              until we've decided which voice the stuff is intended to
548  *              apply to, we don't exactly know what the endpoints of the
549  *              stuff are going to be.  All we know is the "count" values the
550  *              user asked for, which may or may not equal the positions of
551  *              GRPSYLs in the voices.  So we look at voices 1 and 2 and take
552  *              the worst (widest) case as the endpoints.  (This is called only
553  *              when both of these voices exist.  We ignore any voice 3.)
554  */
555
556 int
557 chkallspace(msbeg_p, stuff_p, vno)
558
559 struct MAINLL *msbeg_p; /* staff at beginning of the stuff */
560 struct STUFF *stuff_p;  /* the STUFF */
561 int vno;                /* voice being tested for being all spaces */
562
563 {
564         static RATIONAL tiny = {1, 4 * MAXBASICTIME};
565         struct MAINLL *msend_p;         /* staff at end of the phrase */
566         int timeden;                    /* denom of time sig at end of stuff */
567         RATIONAL begtime, endtime;      /* time into measures of begin & end */
568         RATIONAL temptime;              /* temp var for storing time */
569
570
571         /*
572          * Find what measure this stuff ends in.  Along the way, keep
573          * track of the time signature denominator, in case it changes.
574          */
575         msend_p = getendstuff(msbeg_p, stuff_p, &timeden);
576
577         /*
578          * If we hit a multirest, bail out, arbitrarily returning NO.  This
579          * stuff will be thrown away later anyway.
580          */
581         if (msend_p == 0)
582                 return (NO);
583
584         /*
585          * If the second voice doesn't exist (because vscheme changed),
586          * it's like all spaces in that voice.  So if we're asking about that
587          * voice, return YES.  If asking about the first voice, return NO.
588          */
589         if (msend_p->u.staff_p->groups_p[1] == NULL) {
590                 return (vno == 1 ? YES : NO);
591         }
592
593         /*
594          * Find time values that are sure to contain the stuff.  Take the
595          * outermost values of the two voices.
596          */
597         begtime = lefttime(stuff_p->start.count,
598                                 msbeg_p->u.staff_p->groups_p[0], Score.timeden);
599         temptime = lefttime(stuff_p->start.count,
600                                 msbeg_p->u.staff_p->groups_p[1], Score.timeden);
601         if (LT(temptime, begtime))
602                 begtime = temptime;
603         endtime = righttime(stuff_p->end.count,
604                                 msend_p->u.staff_p->groups_p[0], timeden);
605         temptime = righttime(stuff_p->end.count,
606                                 msend_p->u.staff_p->groups_p[1], timeden);
607         if (GT(temptime, endtime))
608                 endtime = temptime;
609
610         /*
611          * If the beginning and end are in the same measure and at the same
612          * time, this phrase would normally be thrown away later, but we need
613          * to deal with it because the case of a phrase from a grace to its
614          * main note.  It doesn't make sense to ask what a zero time contains,
615          * so to handle this, add a tiny time value to the end time.
616          */
617         if (msbeg_p == msend_p && EQ(begtime, endtime))
618                 endtime = radd(endtime, tiny);
619
620         return (allspace(vno, msbeg_p, begtime, msend_p, endtime));
621 }
622 \f
623 /*
624  * Name:        allspace()
625  *
626  * Abstract:    Finds out if the given voice has space for the given time.
627  *
628  * Returns:     YES or NO
629  *
630  * Description: This function is a multi-measure version of hasspace(), and in
631  *              fact works by calling hasspace() repeatedly.  It is given the
632  *              linked list of groups for the voice in the first measure in
633  *              question.  It checks whether the voice consists entirely of
634  *              spaces from the duration point given for this first measure,
635  *              until the endpoint, which may or may not be in the same measure.
636  */
637
638 int
639 allspace(vno, msbeg_p, begtime, msend_p, endtime)
640
641 int vno;                /* voice number, numbering from voice 1 == 0 */
642 struct MAINLL *msbeg_p; /* point at MLL (staff) where duration begins */
643 RATIONAL begtime;       /* time where duration begins */
644 struct MAINLL *msend_p; /* point at MLL (staff) where duration ends */
645 RATIONAL endtime;       /* time where duration ends */
646
647 {
648         struct MAINLL *mainll_p;                /* point along MLL */
649         int staffno;
650
651
652         /* if the time starts and ends in the same measure, let hasspace do it*/
653         if (msbeg_p == msend_p) {
654                 return (hasspace(msbeg_p->u.staff_p->groups_p[vno],
655                                 begtime, endtime));
656         }
657
658         /*
659          * If the first measure contains non-spaces, return NO.  Rather than
660          * keeping track of time signatures, we're going to pretend that we
661          * are in the longest possible time.  This relies on the fact that
662          * hasspace() in effect assumes that any phony time past the end of
663          * the actual measure is spaces.
664          */
665         if (hasspace(msbeg_p->u.staff_p->groups_p[vno], begtime, Maxtime) == NO)
666                 return (NO);
667
668         staffno = msbeg_p->u.staff_p->staffno;
669
670         /* if any intermediate measures contain non-spaces, return NO */
671         for (mainll_p = msbeg_p->next; mainll_p != 0 && mainll_p != msend_p;
672                         mainll_p = mainll_p->next) {
673
674                 /* skip everything but STAFFs for our staff number */
675                 if (mainll_p->str != S_STAFF ||
676                                 mainll_p->u.staff_p->staffno != staffno)
677                         continue;
678
679                 if (hasspace(mainll_p->u.staff_p->groups_p[vno], Zero, Maxtime)
680                                 == NO)
681                         return (NO);
682         }
683
684         if (mainll_p == 0)
685                 pfatal("bug found in allspace");
686
687         /* the result is now determined by the last measure */
688         return (hasspace(msend_p->u.staff_p->groups_p[vno], Zero, endtime));
689 }
690 \f
691 /*
692  * Name:        getendstuff()
693  *
694  * Abstract:    Find staff and time signature denominator for end of a stuff.
695  *
696  * Returns:     pointer to MLL structure for staff containing end of stuff, or 0
697  *
698  * Description: This function finds the staff for the end of the given stuff.
699  *              As a byproduct, it also finds the denominator of the time
700  *              signature at that place.  If a multirest is encountered, a null
701  *              pointer is returned, and timeden is not guaranteed.
702  *              If the end of the piece is encountered, it returns the last
703  *              staff.
704  */
705
706 struct MAINLL *
707 getendstuff(mainll_p, stuff_p, timeden_p)
708
709 struct MAINLL *mainll_p;/* staff at beginning of stuff, gets changed to end */
710 struct STUFF *stuff_p;  /* the STUFF */
711 int *timeden_p;         /* gets set to denom of time sig at end of stuff */
712
713 {
714         int staffno;            /* staff number where stuff is */
715         struct MAINLL *mst_p;   /* point at the last staffno staff seen */
716         int timenum;            /* remember the last time sig numerator */
717         int b;                  /* count bar lines */
718
719
720         /* bail out if multirest */
721         if (mainll_p->u.staff_p->groups_p[0]->basictime < -1)
722                 return (0);
723
724         timenum = Score.timenum;        /* init to current time sig numerator*/
725         *timeden_p = Score.timeden;     /* init to current time sig denom */
726
727         /* if stuff doesn't cross any bar lines, we can return right away */
728         if (stuff_p->end.bars == 0)
729                 return (mainll_p);
730
731         mst_p = mainll_p;       /* remember last staff of this number */
732
733         staffno = mainll_p->u.staff_p->staffno;
734
735         /*
736          * Count past the right number of  bar lines, keeping the time sig
737          * denominator up to date.
738          */
739         for (b = 0; b < stuff_p->end.bars; b++) {
740                 for (mainll_p = mainll_p->next;
741                                 mainll_p != 0 && mainll_p->str != S_BAR;
742                                 mainll_p = mainll_p->next) {
743
744                         if (mainll_p->str == S_SSV &&
745                                     mainll_p->u.ssv_p->used[TIME] == YES) {
746                                 timenum = mainll_p->u.ssv_p->timenum;
747                                 *timeden_p = mainll_p->u.ssv_p->timeden;
748                         }
749
750                         /* bail out if multirest encountered */
751                         if (mainll_p->str == S_STAFF && mainll_p->u.staff_p->
752                                                 groups_p[0]->basictime < -1)
753                                 return (0);
754
755                         /* remember last staff of this number */
756                         if (mainll_p->str == S_STAFF && mainll_p->u.staff_p->
757                                                 staffno == staffno)
758                                 mst_p = mainll_p;
759                 }
760                 /* if end of song, set to last bar line and return this staff*/
761                 if (mainll_p == 0) {
762                         stuff_p->end.count = timenum + 1;
763                         return (mst_p);
764                 }
765         }
766
767         /*
768          * mainll_p points at the bar line preceding the place where the stuff
769          * ends.  Continue forward to find the correct STAFF.
770          */
771         for (mainll_p = mainll_p->next ;
772                         mainll_p != 0 && mainll_p->str != S_BAR;
773                         mainll_p = mainll_p->next) {
774
775                 if (mainll_p->str == S_SSV &&
776                                 mainll_p->u.ssv_p->used[TIME] == YES)
777                         *timeden_p = mainll_p->u.ssv_p->timeden;
778
779                 if (mainll_p->str == S_STAFF &&
780                                 mainll_p->u.staff_p->staffno == staffno)
781                         break;
782         }
783
784         /* if end of song, set to last bar line and return this staff */
785         if (mainll_p == 0) {
786                 stuff_p->end.count = timenum + 1;
787                 return (mst_p); /* hit end of song, return last meas */
788         }
789         if (mainll_p->str == S_BAR)
790                 pfatal("stuff crosses FEED where number of staffs changes");
791         if (mainll_p->u.staff_p->groups_p[0]->basictime < -1)
792                 return (0);
793
794         return (mainll_p);
795 }
796 \f
797 /*
798  * Name:        lefttime()
799  *
800  * Abstract:    Find time value of the nongrace group left of the given count.
801  *
802  * Returns:     time value into measure
803  *
804  * Description: This function finds the nongrace GRPSYL in the given linked
805  *              list that is at or left of the given count number.  If the
806  *              count is less 1, we return time zero, even though technically
807  *              time zero is to the right of the given count number.
808  */
809
810 static RATIONAL
811 lefttime(count, firstgs_p, timeden)
812
813 double count;                   /* which count of the measure */
814 struct GRPSYL *firstgs_p;       /* first GRPSYL of relevant voice in measure */
815 int timeden;                    /* denominator of current time signature */
816
817 {
818         RATIONAL reqtime;       /* time requested */
819         RATIONAL tottime;       /* total time in measure so far */
820         RATIONAL otottime;      /* old total time in measure so far */
821         struct GRPSYL *gs_p;    /* point along group list */
822         struct GRPSYL *ogs_p;   /* (old) point along group list */
823
824
825         /* skip over any initial grace groups */
826         if (firstgs_p->grpvalue == GV_ZERO)
827                 firstgs_p = nextnongrace(firstgs_p);
828
829         /* if at or before the first count, have to use first group */
830         if (count <= 1)
831                 return (Zero);
832
833         /*
834          * Get requested time to the nearest half of the smallest fraction of a
835          * count that a user can specify, +1, in lowest terms.  The +1 is so
836          * that if the user isn't too accurate, we still land on the intended
837          * group.
838          */
839         reqtime.n = 2 * MAXBASICTIME * (count - 1) + 0.5 + 1.0;
840         reqtime.d = 2 * MAXBASICTIME * timeden;
841         rred(&reqtime);
842
843         /*
844          * Loop through this voice accumulating time values.  As soon as we
845          * equal or exceed the requested time value, return the previous
846          * group's time.
847          */
848         otottime = tottime = Zero;
849         for (ogs_p = firstgs_p, gs_p = nextnongrace(ogs_p); gs_p != 0;
850                                 ogs_p = gs_p, gs_p = nextnongrace(gs_p)) {
851                 otottime = tottime;
852                 tottime = radd(tottime, ogs_p->fulltime);
853                 if (GE(tottime, reqtime))
854                         return (otottime);
855         }
856
857         /* requested time is after last group; return time of last group */
858         return (otottime);
859 }
860 \f
861 /*
862  * Name:        righttime()
863  *
864  * Abstract:    Find time value of the nongrace group right of the given count.
865  *
866  * Returns:     time value into measure
867  *
868  * Description: This function finds the nongrace GRPSYL in the given linked
869  *              list that is at or right of the given count number.  If the
870  *              count is greater then the rightmost group in the measure, we
871  *              return the time up to the rightmost group, even though
872  *              technically that time is to the left of the given count number.
873  */
874
875 static RATIONAL
876 righttime(count, firstgs_p, timeden)
877
878 double count;                   /* which count of the measure */
879 struct GRPSYL *firstgs_p;       /* first GRPSYL of relevant voice in measure */
880 int timeden;                    /* denominator of current time signature */
881
882 {
883         RATIONAL reqtime;       /* time requested */
884         RATIONAL tottime;       /* total time in measure so far */
885         struct GRPSYL *gs_p;    /* point along group list */
886         struct GRPSYL *ogs_p;   /* (old) point along group list */
887
888
889         /* skip over any initial grace groups */
890         if (firstgs_p->grpvalue == GV_ZERO)
891                 firstgs_p = nextnongrace(firstgs_p);
892
893         /* if at or before the first count, use first group */
894         if (count <= 1)
895                 return (Zero);
896
897         /*
898          * Get requested time to the nearest half of the smallest fraction of a
899          * count that a user can specify, -1, in lowest terms.  The -1 is so
900          * that if the user isn't too accurate, we still land on the intended
901          * group.
902          */
903         reqtime.n = 2 * MAXBASICTIME * (count - 1) + 0.5 - 1.0;
904         reqtime.d = 2 * MAXBASICTIME * timeden;
905         rred(&reqtime);
906
907         /*
908          * Loop through this voice accumulating time values.  As soon as we
909          * equal or exceed the requested time value, return that new time,
910          * although don't go beyond the last group's time value.
911          */
912         tottime = Zero;
913         for (ogs_p = firstgs_p, gs_p = nextnongrace(ogs_p); gs_p != 0;
914                                 ogs_p = gs_p, gs_p = nextnongrace(gs_p)) {
915                 tottime = radd(tottime, ogs_p->fulltime);
916                 if (GE(tottime, reqtime))
917                         return (tottime);
918         }
919
920         /* requested time is after last group; but must return last group */
921         return (tottime);
922 }
923 \f
924 /*
925  * Name:        accdimen()
926  *
927  * Abstract:    Find the dimensions of a note's accidental.
928  *
929  * Returns:     void
930  *
931  * Description: This function finds the ascent, descent, and width of an
932  *              accidental, and returns them through pointers.  If a pointer
933  *              is null, it doesn't try to fill it in.  An accidental char of
934  *              '\0' gives zero for each dimension.  The function takes into
935  *              account whether the accidental is normal or small size, and
936  *              whether it has parentheses around it.
937  *              NOTE:  This function ignores staffscale.
938  */
939
940 void
941 accdimen(note_p, ascent_p, descent_p, width_p)
942
943 struct NOTE *note_p;            /* the note whose accidental we're working on*/
944 float *ascent_p;                /* ascent, to be filled in */
945 float *descent_p;               /* descent, to be filled in */
946 float *width_p;                 /* width, to be filled in */
947
948 {
949         char accchar;           /* accidental character number */
950         int size;               /* which size of character */
951         float halfhigh;         /* half the height of a parenthesis */
952
953
954         if (note_p->accidental == '\0') {
955                 if (ascent_p != 0) {
956                         *ascent_p  = 0.0;
957                 }
958                 if (descent_p != 0) {
959                         *descent_p = 0.0;
960                 }
961                 if (width_p != 0) {
962                         *width_p   = 0.0;
963                 }
964                 return;
965         }
966
967         /* find character name and size of this accidental */
968         accchar = acc2char(note_p->accidental);
969         size = (note_p->notesize == GS_NORMAL ? DFLT_SIZE : SMALLSIZE);
970
971         /* get the requested dimensions of this accidental */
972         if (ascent_p != 0) {
973                 *ascent_p  =  ascent(FONT_MUSIC, size, accchar);
974         }
975         if (descent_p != 0) {
976                 *descent_p = descent(FONT_MUSIC, size, accchar);
977         }
978         if (width_p != 0) {
979                 *width_p   =   width(FONT_MUSIC, size, accchar);
980         }
981
982         /*
983          * If it has parentheses around it, account for that.  Assume the left
984          * and right parens are symmetrical.  They will be centered on the line
985          * or space of the note.
986          */
987         if (note_p->acc_has_paren) {
988                 if (width_p != 0) {
989                         *width_p += 2 * width(FONT_TR, size, '(');
990                 }
991                 halfhigh = height(FONT_TR, size, '(') / 2.0;
992                 if (ascent_p != 0 && halfhigh > *ascent_p) {
993                         *ascent_p = halfhigh;
994                 }
995                 if (descent_p != 0 && halfhigh > *descent_p) {
996                         *descent_p = halfhigh;
997                 }
998         }
999 }
1000 \f
1001 /*
1002  * Name:        staffvertspace()
1003  *
1004  * Abstract:    Find the minimum amount of vertical space a staff should have.
1005  *
1006  * Returns:     the amount of vertical distance in inches
1007  *
1008  * Description: This function finds the minimum amount of vertical space that
1009  *              should be allocated for a staff, based on how many lines it has
1010  *              and whether it is tablature.  This does not take into account
1011  *              the extra space required by things sticking out farther; it's
1012  *              just for the staff itself, plus the extra white space required
1013  *              by staffs that have few lines.  The SSVs must be up to date.
1014  *              NOTE:  This function takes staffscale into account.
1015  */
1016
1017 double
1018 staffvertspace(s)
1019
1020 int s;                          /* staff number */
1021
1022 {
1023         float space;            /* the answer */
1024
1025
1026         /*
1027          * Base space on number of steps between top and bottom lines.  But for
1028          * tablature, it must be scaled because the lines are farther apart.
1029          */
1030         space = (svpath(s, STAFFLINES)->stafflines - 1) * 2 * STEPSIZE;
1031         if (is_tab_staff(s))
1032                 space *= TABRATIO;
1033
1034         /* but don't ever return less than a (scaled) regular 5 line staff */
1035         return (svpath(s, STAFFSCALE)->staffscale * MAX(space, 8.0 * STEPSIZE));
1036 }
1037 \f
1038 /*
1039  * Name:        halfstaffhi()
1040  *
1041  * Abstract:    Find half of the staff height.
1042  *
1043  * Returns:     half the staff height in inches
1044  *
1045  * Description: This function finds half of the staff's height, based on how
1046  *              many lines it has and whether it is tablature.  This does not
1047  *              take into account the extra space required by things sticking
1048  *              out farther; it's just for the staff itself, except that one
1049  *              line staffs are given a minimum instead of the zero you would
1050  *              expect.  The SSVs must be up to date.
1051  *              NOTE:  This function takes staffscale into account.
1052  */
1053
1054 double
1055 halfstaffhi(s)
1056
1057 int s;                          /* staff number */
1058
1059 {
1060         float space;            /* the answer */
1061
1062
1063         /*
1064          * Base space on the number of steps between the top line and the
1065          * middle of the staff.  But for tablature, it must be scaled because
1066          * the lines are farther apart.
1067          */
1068         space = (svpath(s, STAFFLINES)->stafflines - 1) * STEPSIZE;
1069         if (is_tab_staff(s))
1070                 space *= TABRATIO;
1071
1072         /* but don't ever return less than one (scaled) stepsize */
1073         return (MAX(space, STEPSIZE) * svpath(s, STAFFSCALE)->staffscale);
1074 }
1075 \f
1076 /*
1077  * Name:        ratbend()
1078  *
1079  * Abstract:    Convert a bend distance to rational.
1080  *
1081  * Returns:     the rational number answer; 0/1 if null bend or no bend
1082  *
1083  * Description: This function, given a NOTE structure from a tab staff, returns
1084  *              the amount of the bend (if any) as a rational number.
1085  */
1086
1087 RATIONAL
1088 ratbend(note_p)
1089
1090 struct NOTE *note_p;
1091
1092 {
1093         RATIONAL answer;
1094
1095
1096         if (note_p->BEND == 0)
1097                 return (Zero);
1098
1099         answer.d = BENDDEN(*note_p);
1100         answer.n = BENDNUM(*note_p) + BENDINT(*note_p) * answer.d;
1101         rred(&answer);
1102
1103         return (answer);
1104 }
1105 \f
1106 /*
1107  * Name:        notehorz()
1108  *
1109  * Abstract:    Find horizontal boundary of note and associated things.
1110  *
1111  * Returns:     the RE or RW
1112  *
1113  * Description: This function finds the horizontal boundary of a note,
1114  *              including accidentals, dots, etc., all the things that can be
1115  *              on the note.  The note's own RE and RW only tell about the note
1116  *              head itself.
1117  *              NOTE:  This function takes staffscale into account.  The SSVs
1118  *              need not be up to date, but Staffscale and Stdpad must be set.
1119  */
1120
1121 double
1122 notehorz(gs_p, note_p, coord)
1123
1124 struct GRPSYL *gs_p;            /* the group the note is in */
1125 struct NOTE *note_p;            /* point at the note */
1126 int coord;                      /* RE or RW */
1127
1128 {
1129         int s;                  /* index into slurtolist */
1130         double h;               /* the answer */
1131
1132
1133         if (coord == RE) {
1134                 if (note_p->note_has_paren == YES &&
1135                                         ! is_tab_staff(gs_p->staffno)) {
1136                         /*
1137                          * If there are parens around the note, start there.
1138                          * Note: this field does not apply on tab staff; it
1139                          * is only there for carrying over to tabnote staff.
1140                          * Tab staff uses FRET_HAS_PAREN, and this distance is
1141                          * included in the size of the "note" (fret) itself.
1142                          */
1143                         h = note_p->erparen;
1144                 } else  {
1145                         /*
1146                          * If non-tablature and there are dots, start from the
1147                          * first dot.  Otherwise start from the note.
1148                          */
1149                         if (is_tab_staff(gs_p->staffno) == NO &&
1150                                         gs_p->dots > 0) {
1151                                 h = gs_p->xdotr + 6 * Stdpad;
1152                                 if (gs_p->dots > 1) {
1153                                         h += (gs_p->dots - 1) * (2 * Stdpad +
1154                                         width(FONT_MUSIC, DFLT_SIZE, C_DOT));
1155                                 }
1156                         } else {
1157                                 h = note_p->c[RE] + Stdpad;
1158                         }
1159                 }
1160
1161                 /*
1162                  * If this note has a slur to nowhere (and there can be at most
1163                  * one such), include its length.
1164                  */
1165                 for (s = 0; s < note_p->nslurto; s++) {
1166                         if (note_p->slurtolist[s].octave == OUT_UPWARD ||
1167                             note_p->slurtolist[s].octave == OUT_DOWNWARD) {
1168                                 h += Staffscale * (SLIDEXLEN + STDPAD);
1169                                 break;
1170                         }
1171                 }
1172
1173         } else {        /* RW */
1174
1175                 if (note_p->note_has_paren == YES &&
1176                                         ! is_tab_staff(gs_p->staffno)) {
1177                         /* if parens around note, start there */
1178                         h = note_p->wlparen;
1179                 } else if (is_tab_staff(gs_p->staffno) == NO &&
1180                                 note_p->accidental != '\0') {
1181                         /* if there's an accidental, start there */
1182                         /* (this includes any parens around the accidental) */
1183                         h = note_p->waccr;
1184                 } else {
1185                         /* the note head itself, with padding */
1186                         h = note_p->c[RW] - Stdpad;
1187                 }
1188
1189                 /*
1190                  * If this note has a slur from nowhere (and there can be at
1191                  * most one such), include its length.
1192                  */
1193                 for (s = 0; s < note_p->nslurto; s++) {
1194                         if (note_p->slurtolist[s].octave == IN_UPWARD ||
1195                             note_p->slurtolist[s].octave == IN_DOWNWARD) {
1196                                 h -= Staffscale * (SLIDEXLEN + STDPAD);
1197                                 break;
1198                         }
1199                 }
1200         }
1201
1202         return (h);
1203 }
1204 \f
1205 /*
1206  * Name:        allsmall()
1207  *
1208  * Abstract:    Do the given groups (of notes) consist entirely of small notes?
1209  *
1210  * Returns:     YES or NO
1211  *
1212  * Description: This function is given pointer to two GRPSYLs in a linked list.
1213  *              They may point to the same GRPSYL, or the second may point to a
1214  *              later GRPSYL in the list.  The function returns YES if all the
1215  *              notes in these GRPSYLs and any intervening GRPSYLs are small.
1216  *              Any GRPSYLs that are not for notes are ignored.
1217  */
1218
1219 int
1220 allsmall(gs1_p, gs2_p)
1221
1222 struct GRPSYL *gs1_p;   /* starting group */
1223 struct GRPSYL *gs2_p;   /* ending group (may be same as starting group) */
1224
1225 {
1226         struct GRPSYL *gs_p;    /* point along the list */
1227         int n;                  /* index into notelist */
1228
1229
1230         /* check every group, and return NO if anything is normal size */
1231         for (gs_p = gs1_p; gs_p != gs2_p->next; gs_p = gs_p->next) {
1232                 if (gs_p->grpcont == GC_NOTES && gs_p->grpsize == GS_NORMAL) {
1233                         for (n = 0; n < gs_p->nnotes; n++) {
1234                                 if (gs_p->notelist[n].notesize == GS_NORMAL)
1235                                         return (NO);
1236                         }
1237                 }
1238         }
1239
1240         return (YES);   /* everything must have been small */
1241 }
1242 \f
1243 /*
1244  * Name:        finalstemadjust()
1245  *
1246  * Abstract:    Make final adjustments to the stem length.
1247  *
1248  * Returns:     void
1249  *
1250  * Description: This function makes final adjustments to the stem length that
1251  *              all the cases have in common.  Coming in, it is set to the
1252  *              stem length not counting the part between notes of a multinote
1253  *              group, and it doesn't account for the thickness of a beam.
1254  *              The SSVs must be up to date.
1255  *              NOTE:  This function takes staffscale into account.
1256  */
1257
1258 void
1259 finalstemadjust(gs_p)
1260
1261 struct GRPSYL *gs_p;    /* group whose stemlen should be adjusted */
1262
1263 {
1264         float stepdiff;         /* distance between outer notes in steps */
1265
1266
1267         /* if it is negative (note on wrong side of beam), zap it */
1268         if (gs_p->stemlen < 0)
1269                 gs_p->stemlen = 0;
1270
1271         /* add distance between outer notes of group */
1272         stepdiff = gs_p->notelist[0].c[RY] -
1273                         gs_p->notelist[ gs_p->nnotes - 1 ].c[RY];
1274         gs_p->stemlen += stepdiff;
1275
1276         /*
1277          * Decr the length by half the thickness of the beam, but don't let it
1278          * get less than the distance between the outer notes of the group.
1279          */
1280         gs_p->stemlen -= (W_WIDE * POINT / 2.0) *
1281                         (gs_p->grpsize == GS_NORMAL ? 1.0 : SM_FACTOR) *
1282                         svpath(gs_p->staffno, STAFFSCALE)->staffscale;
1283         gs_p->stemlen = MAX(gs_p->stemlen, stepdiff);
1284 }
1285 \f
1286 /*
1287  * Name:        getstemshift()
1288  *
1289  * Abstract:    Find how far a stem is from the group's X coordinate.
1290  *
1291  * Returns:     the distance in inches
1292  *
1293  * Description: This function finds how far a group's stem is shifted
1294  *              horizontally from the group's X coordinate.
1295  *              NOTE:  This function takes staffscale into account.
1296  */
1297
1298 double
1299 getstemshift(gs_p)
1300
1301 struct GRPSYL *gs_p;    /* group whose stemlen should be adjusted */
1302
1303 {
1304         /* return half the width of the widest note in the group */
1305         return (svpath(gs_p->staffno, STAFFSCALE)->staffscale *
1306                         widest_head(gs_p) / 2.0);
1307 }
1308 \f
1309 /*
1310  * Name:        vscheme_voices()
1311  *
1312  * Abstract:    Given a vscheme, how many voices are in it?
1313  *
1314  * Returns:     number of voices
1315  *
1316  * Description: This function is given one of the valid vschemes, and it
1317  *              returns the number of voices that vscheme allows.
1318  */
1319
1320 int
1321 vscheme_voices(vscheme)
1322
1323 int vscheme;            /* the given vscheme */
1324
1325 {
1326         switch (vscheme) {
1327         case V_1:
1328                 return (1);
1329
1330         case V_2OPSTEM:
1331         case V_2FREESTEM:
1332                 return (2);
1333
1334         case V_3OPSTEM:
1335         case V_3FREESTEM:
1336                 return (3);
1337
1338         default:
1339                 pfatal("invalid vscheme in vscheme_voices()");
1340         }
1341
1342         return (0);
1343 }
1344 \f
1345 /*
1346  * Name:        chmgrp2staffm()
1347  *
1348  * Abstract:    Given a chord and group, find the group's staff.
1349  *
1350  * Returns:     pointer to staff's MLL item
1351  *
1352  * Description: This function is given the MLL item for a chord, and a group
1353  *              connected to the chord.  It returns the MLL item for the staff
1354  *              that the group is connected to.  The group can belong to any of
1355  *              the staff's voices.
1356  */
1357
1358 struct MAINLL *
1359 chmgrp2staffm(mll_p, gs_p)
1360
1361 struct MAINLL *mll_p;           /* starts as MLL for the chord */
1362 struct GRPSYL *gs_p;            /* starts as GRPSYL the given group */
1363
1364 {
1365         /* find the first group in this measure */
1366         for ( ; gs_p->prev != 0; gs_p = gs_p->prev)
1367                 ;
1368
1369         /* find the staff that it belongs to */
1370         for ( ; mll_p != 0; mll_p = mll_p->next) {
1371
1372                 if (mll_p->str == S_STAFF &&
1373                 (mll_p->u.staff_p->groups_p[0] == gs_p ||
1374                  mll_p->u.staff_p->groups_p[1] == gs_p ||
1375                  mll_p->u.staff_p->groups_p[2] == gs_p))
1376                         break;
1377         }
1378         if (mll_p == 0)
1379                 pfatal("can't find staff in chmgrp2staffm");
1380
1381         return (mll_p);
1382 }
1383 \f
1384 /*
1385  * Name:        shiftgs()
1386  *
1387  * Abstract:    Shift a GRPSYL's relative horizontal coords.
1388  *
1389  * Returns:     void
1390  *
1391  * Description: This function is a GRPSYL and a shift amount.  It shifts the
1392  *              GRPSYL's relative horizontal coords by that amount, also
1393  *              including any preceding grace GRPSYLs.
1394  */
1395
1396 void
1397 shiftgs(gs_p, shift)
1398
1399 struct GRPSYL *gs_p;            /* the main GRPSYL */
1400 double shift;
1401
1402 {
1403         struct GRPSYL *ggs_p;           /* point at a grace group */
1404
1405
1406         gs_p->c[RX] += shift;
1407         gs_p->c[RW] += shift;
1408         gs_p->c[RE] += shift;
1409
1410         /* apply shift to any preceding grace groups */
1411         for (ggs_p = gs_p->prev; ggs_p != 0 && ggs_p->grpvalue == GV_ZERO;
1412                                 ggs_p = ggs_p->prev) {
1413                 ggs_p->c[RX] += shift;
1414                 ggs_p->c[RW] += shift;
1415                 ggs_p->c[RE] += shift;
1416         }
1417 }
1418 \f
1419 /*
1420  * Name:        nearestline()
1421  *
1422  * Abstract:    Round a vertical offset to the nearest staff line.
1423  *
1424  * Returns:     the resulting offset
1425  *
1426  * Description: This function rounds its parameter off to a multiple of 2
1427  *              stepsizes.
1428  *              NOTE:  This function takes staffscale into account.  The SSVs
1429  *              need not be up to date, but Stepsize must be set.
1430  */
1431
1432 double
1433 nearestline(offset)
1434
1435 double offset;                  /* offset from center staff line */
1436
1437 {
1438         if (offset >= 0) {
1439                 offset /= (2 * Stepsize);
1440                 offset = (int)(offset + 0.5);
1441                 offset *= (2 * Stepsize);
1442         } else {
1443                 offset = -offset;
1444                 offset /= (2 * Stepsize);
1445                 offset = (int)(offset + 0.5);
1446                 offset *= (2 * Stepsize);
1447                 offset = -offset;
1448         }
1449
1450         return (offset);
1451 }
1452 \f
1453 /*
1454  * Name:        vfyoffset()
1455  *
1456  * Abstract:    Verify horizontal offsets are not in conflict.
1457  *
1458  * Returns:     void
1459  *
1460  * Description: This function prints a warning if the horizontal offsets of
1461  *              voices 1 and 2 are in conflict.  In that case it also zaps
1462  *              the bad offsets.
1463  */
1464
1465 void
1466 vfyoffset(g_p)
1467
1468 struct GRPSYL *g_p[];           /* array of pointers to two groups */
1469
1470 {
1471         /* the only errors are cases where "+" and "-" are used */
1472         if (g_p[0]->ho_usage != HO_LEFT && g_p[0]->ho_usage != HO_RIGHT)
1473                 return;
1474
1475         /* can't both be "+" or both be "-" */
1476         if (g_p[0]->ho_usage == g_p[1]->ho_usage) {
1477
1478                 l_warning(
1479                         g_p[1]->inputfile, g_p[1]->inputlineno,
1480                         "voices 1 and 2 cannot both have horizontal offset '%c'; ignoring them",
1481                         g_p[0]->ho_usage == HO_LEFT ? '-' :'+');
1482
1483                 g_p[0]->ho_usage = HO_NONE;
1484                 g_p[1]->ho_usage = HO_NONE;
1485         }
1486 }
1487 \f
1488 /*
1489  * Name:        adjslope()
1490  *
1491  * Abstract:    Adjust the slope of a beam.
1492  *
1493  * Returns:     the new slope
1494  *
1495  * Description: This function is given the slope of a beam as determined by
1496  *              linear regression.  It adjusts it according to the "beamslope"
1497  *              parameter.
1498  */
1499
1500 double
1501 adjslope(g_p, oldslope, betweencsb)
1502
1503 struct GRPSYL *g_p;     /* pointer to GRPSYL to get staff and voice from */
1504 double oldslope;        /* the given slope */
1505 int betweencsb;         /* is this beam CSB and between the staffs? */
1506
1507 {
1508         struct SSV *ssv_p;      /* for getting fact and max */
1509         float beamfact;         /* to multiply by */
1510         float beammax;          /* max angle in degrees */
1511         float newangle;         /* the adjusted angle */
1512
1513
1514         /* find parameter values */
1515         ssv_p = vvpath(g_p->staffno, g_p->vno, BEAMSLOPE);
1516         beamfact = ssv_p->beamfact;
1517         beammax  = ssv_p->beammax;
1518
1519         /*
1520          * If cross staff beaming and the beam is between the staffs, we allow
1521          * a somewhat bigger angle, because it may be necessary to avoid
1522          * collisions.
1523          */
1524         if (betweencsb == YES)
1525                 beammax *= 1.4;
1526
1527         /* new angle = old angle * beamfact */
1528         newangle = (atan(oldslope) * 180.0 / PI) * beamfact;
1529
1530         /* force it to stay within the limit */
1531         if (newangle > beammax)
1532                 newangle = beammax;
1533         else if (newangle < -beammax)
1534                 newangle = -beammax;
1535
1536         /* return as slope */
1537         return (tan(newangle * PI / 180.0));
1538 }
1539 \f
1540 /*
1541  * Name:        curve_y_at_x()
1542  *
1543  * Abstract:    Given a curve and an X value, return the Y value there.
1544  *
1545  * Returns:     the Y value
1546  *
1547  * Description: This function should only be called for curves where the X
1548  *              value of each point in the curve list is greater than the
1549  *              previous point's X value, although it's okay if the curve
1550  *              itself is not strictly increasing in X value all the time as
1551  *              you go from the start to the end.
1552  *
1553  *              If the X value given is less than the first point's, it returns
1554  *              the Y of the first point.  If the X value is greater than the
1555  *              last point's, it returns the Y of the last point.  Otherwise,
1556  *              it returns a Y value of the curve at that X value.  I say "a"
1557  *              Y value, because if the curve isn't strictly increasing, there
1558  *              can be multiple answers, and it just returns one of them.
1559  *
1560  *              The function assumes that the curve points will be connected by
1561  *              cubic curves, according to the algorithm in calccurve() and
1562  *              findcontrol().
1563  */
1564
1565 double
1566 curve_y_at_x(first_p, x)
1567
1568 struct CRVLIST *first_p;        /* left endpoint of curve */
1569 double x;                       /* X coord at which we need Y */
1570
1571 {
1572         float y;                /* the answer */
1573         float a, b, c;          /* coefficients for a cubic */
1574         struct CRVLIST *left_p, *right_p; /* endpoints of a cubic segment */
1575         float rotangle;         /* rotate new system to get old (in radians) */
1576         float tranx, trany;     /* a point translated to another coord system */
1577         float pointx, pointy;   /* trans & rotated in another coord system */
1578         float lineslope, intercept;     /* of a line through the given x */
1579         float cos_rotangle, sin_rotangle;       /* for saving these values */
1580         float deltax, deltay;   /* of endpoints of segment between 2 points */
1581         float len;              /* length of segment between 2 points */
1582
1583
1584         /*
1585          * If the first point of the curve is at or already beyond the given x,
1586          * return the first point's y.
1587          */
1588         if (first_p->x >= x) {
1589                 return (first_p->y);
1590         }
1591         right_p = 0;    /* for lint */
1592         for (left_p = first_p; left_p->next != 0; left_p = left_p->next) {
1593                 right_p = left_p->next;
1594                 /* if x is right at this point, use this point's y */
1595                 if (right_p->x == x) {
1596                         return (right_p->y);
1597                 }
1598                 /* if x is within this interval, break out */
1599                 if (left_p->x < x && x < right_p->x) {
1600                         break;
1601                 }
1602         }
1603         /* if this happens, x is beyond the last point, so use last point's y */
1604         if (left_p->next == 0) {
1605                 return (left_p->y);
1606         }
1607
1608         /*
1609          * The given x is between the x coords of two of the points in the
1610          * curvelist.  So we need to find the cubic arc that calccurve() and
1611          * findcontrol() would use, if this curve is going to be used.  The
1612          * cubic arc is determined in a translated/rotated coordinate system
1613          * where left_p is (0,0) and right_p is on the positive X axix.
1614          * rotangle is the angle from the segment between left_p and right_p
1615          * to the real X axis.  The cubic, in the translated/rotated system, is
1616          * y = a x^3 + b x^2 + c x.  It turns out that the constant term is
1617          * always zero.
1618          */
1619         rotangle = findcubic(left_p, right_p, &a, &b, &c);
1620
1621         /*
1622          * If left_p->y == right_p->y, rotangle is zero, meaning no rotation was
1623          * necessary, only translation.  In that case we can simply plug into
1624          * the cubic we found, adjusting for the translation.  A fudge factor is
1625          * needed so that we don't take the tangent of almost 90 degrees below.
1626          */
1627         if (fabs(rotangle) < 0.001) {
1628                 pointx = x - left_p->x;
1629                 pointy = ((a * pointx + b) * pointx + c) * pointx;
1630                 y = pointy + left_p->y;
1631                 return (y);
1632         }
1633
1634         /*
1635          * Rotation was necessary.  In the original coord system, picture a
1636          * vertical line at the given x value.  It intersects the cubic,
1637          * possibly in more than one place.  We want the y value at the
1638          * intersection.  In the translated/rotated system, this line has a
1639          * slope as determine below.
1640          */
1641         if (rotangle < 0.0) {
1642                 lineslope = tan(PI / 2.0 + rotangle);
1643         } else {
1644                 lineslope = tan(-PI / 2.0 + rotangle);
1645         }
1646
1647         /*
1648          * In the real coord system, the vertical line hits (x, 0).  Find this
1649          * point in the translated/rotated system.
1650          */
1651         /* first translate */
1652         tranx = x - left_p->x;
1653         trany = -left_p->y;
1654         /* then rotate */
1655         cos_rotangle = cos(rotangle);   /* save to avoid recalculation */
1656         sin_rotangle = sin(rotangle);
1657         pointx = tranx * cos_rotangle - trany * sin_rotangle;
1658         pointy = trany * cos_rotangle + tranx * sin_rotangle;
1659
1660         /* find Y intercept in the translated/rotated system */
1661         intercept = pointy - lineslope * pointx;
1662
1663         /*
1664          * Now, in the tran/rot coord system, we need to find the intersection
1665          * of this line
1666          *      y  =  lineslope * x  +  intercept
1667          * and the cubic
1668          *      y  =  a * x^3  +  b * x^2  +  c * x
1669          * Setting the two values of y equal, we get
1670          *      lineslope * x  +  intercept  =  a * x^3  +  b * x^2  +  c * x
1671          * or
1672          *      a * x^3  +  b * x^2  + (c - lineslope) * x  -  intercept  =  0
1673          */
1674         /* find intersection point in the tran/rot coord system */
1675         deltax = right_p->x - left_p->x;
1676         deltay = right_p->y - left_p->y;
1677         len = sqrt(SQUARED(deltax) + SQUARED(deltay));
1678         pointx = solvecubic(a, b, c-lineslope, -intercept,
1679                         0.0, len, Stdpad / 2.0);
1680         pointy = lineslope * pointx + intercept;
1681
1682         /* rotate backwards, getting Y value */
1683         trany = pointy * cos_rotangle - pointx * sin_rotangle;
1684
1685         /* translate back to the original coord system */
1686         y = trany + left_p->y;
1687
1688         return (y);
1689 }
1690 \f
1691 /*
1692  * Name:        findcubic()
1693  *
1694  * Abstract:    Given neighboring curve points, find cubic and rotation angle.
1695  *
1696  * Returns:     angle from new coord system's X axis to old system's (radians)
1697  *
1698  * Description: This function uses a new coordinate system, where the left
1699  *              curve point is (0, 0), and the right curve point is on the
1700  *              positive X axis.  It finds the coefficients for the cubic arc
1701  *              that will be put through these points.  It returns the angle
1702  *              that the old coord system needs to be rotated by to get to
1703  *              the new system.
1704  */
1705
1706 double
1707 findcubic(left_p, right_p, a_p, b_p, c_p)
1708
1709 struct CRVLIST *left_p;         /* left endpoint of cubic arc */
1710 struct CRVLIST *right_p;        /* right endpoint of cubic arc */
1711 float *a_p, *b_p, *c_p;         /* return the answers here, the coefficients */
1712
1713 {
1714         double langle;          /* half angle from prev segment to this one */
1715         double rangle;          /* half angle from this segment to next one */
1716         float deltax, deltay;   /* for this segment */
1717         float len;              /* of this segment */
1718         float lslope, rslope;   /* slope of tangent line at left & right point*/
1719         float thisang, prevang, nextang; /* angle of segment with horizontal */
1720
1721
1722         langle = rangle = 0.0;  /* for lint */
1723
1724         /* get angle of this segment */
1725         thisang = atan((right_p->y - left_p->y) / (right_p->x - left_p->x));
1726
1727         if (left_p->prev != 0) {
1728                 /* there is a previous segment; find its angle */
1729                 prevang = atan((left_p->y - left_p->prev->y) /
1730                                (left_p->x - left_p->prev->x));
1731                 /* half the change in angle */
1732                 langle = (thisang - prevang) / 2.0;
1733         }
1734         if (right_p->next != 0) {
1735                 /* there is a next segment; find its angle */
1736                 nextang = atan((right_p->next->y - right_p->y) /
1737                                (right_p->next->x - right_p->x));
1738                 /* half the change in angle */
1739                 rangle = (nextang - thisang) / 2.0;
1740         }
1741         if (left_p->prev == 0) {
1742                 /* no previous segment; use same angle as on the right */
1743                 langle = rangle;
1744         }
1745         if (right_p->next == 0) {
1746                 /* no next segment; use same angle as on the left */
1747                 rangle = langle;
1748         }
1749
1750         /* get lengths of this segment */
1751         deltax = right_p->x - left_p->x;
1752         deltay = right_p->y - left_p->y;
1753         len = sqrt(SQUARED(deltax) + SQUARED(deltay));
1754
1755         /*
1756          * Rotate and translate the axes so that the starting point (left_p)
1757          * is at the origin, and the ending point (right_p) is on the positive
1758          * x axis.  Their coords are (0, 0) and (len, 0).  We are going to
1759          * find a cubic equation that intersects the endpoints, and has the
1760          * required slope at those points.  The equation is
1761          *      y  =  a x^3  +  b x^2  +  c x  +  d
1762          * so the slope is
1763          *      y' =  3 a x^2  +  2 b x  +  c
1764          * By plugging the two points into these, you get 4 equations in the 4
1765          * unknowns a, b, c, d.
1766          */
1767         /* find the slope of the tangent lines at the first & second points */
1768         lslope = -tan(langle);
1769         rslope = tan(rangle);
1770
1771         /* set values of a, b, c (d turns out to be always 0) */
1772         *a_p = (lslope + rslope) / SQUARED(len);
1773         *b_p = (-2.0 * lslope - rslope) / len;
1774         *c_p = lslope;
1775
1776         return (-thisang);
1777 }
1778 \f
1779 /*
1780  * Name:        solvecubic()
1781  *
1782  * Abstract:    Find a solution to a cubic equation within a given interval.
1783  *
1784  * Returns:     the solution
1785  *
1786  * Description: This function is given the coefficients of a cubic equation and
1787  *              the boundaries of an interval.  The function must be positive
1788  *              at one end and negative at the other (or zero is okay at
1789  *              either).  It uses the "modified regula falsi" algorithm to find
1790  *              a solution, meaning that it keeps narrowing down the interval.
1791  *              It stops when the inverval size <= the threshhold given.  But
1792  *              in case something goes wrong, it also stops after 20 loops.
1793  */
1794
1795 double
1796 solvecubic(a, b, c, d, lo, hi, thresh)
1797
1798 double a, b, c, d;      /* in equation   a x^3 + b x^2 + c x + d = 0  */
1799 double lo, hi;          /* low and high boundaries of interval to look in */
1800 double thresh;          /* how close must result be to the true answer */
1801
1802 #define FUNC(x) (((a * x + b) * x + c) * x + d)
1803 {
1804         float lovert, hivert;   /* y values */
1805         float mid, midvert;     /* a point in the middle and its y value */
1806         float oldmidvert;       /* midvert in previous loop */
1807         int n;
1808
1809
1810         lovert = FUNC(lo);
1811         hivert = FUNC(hi);
1812
1813         /*
1814          * If the function is positive at both endpoints or negative at both
1815          * endpoints, it was called incorrectly.  But we're going to allow for
1816          * a small violation of this due to presumed roundoff error.  If one
1817          * endpoint if "very near" zero, we'll pretend it was zero and return
1818          * it as the solution.
1819          */
1820         if (lovert * hivert > 0.0) {
1821                 if (fabs(lovert) < thresh)
1822                         return (lo);
1823                 if (fabs(hivert) < thresh)
1824                         return (hi);
1825                 pfatal("solvecubic was called with an invalid interval");
1826         }
1827
1828         mid = lo;
1829         midvert = lovert;
1830
1831         for (n = 0; n < 20 && hi - lo > thresh; n++) {
1832                 oldmidvert = midvert;
1833
1834                 /*
1835                  * Find a point somewhere in the interval by passing a segment
1836                  * through (lo, lovert) and (hi, hivert) and seeing where it
1837                  * hits the X axis.
1838                  */
1839                 mid = (lovert * hi - hivert * lo) / (lovert - hivert);
1840                 midvert = FUNC(mid);
1841
1842                 /*
1843                  * Set either the hi or the lo equal to the mid.  If the value
1844                  * at mid is the same sign as the previous one, divide the
1845                  * vert value by 2, so we can eventually get the segment to
1846                  * hit on the other side.
1847                  */
1848                 if ((lovert > 0.0) != (midvert > 0.0)) {
1849                         hi = mid;
1850                         hivert = midvert;
1851                         if ((midvert > 0.0) == (oldmidvert > 0.0)) {
1852                                 lovert /= 2.0;
1853                         }
1854                 } else {
1855                         lo = mid;
1856                         lovert = midvert;
1857                         if ((midvert > 0.0) == (oldmidvert > 0.0)) {
1858                                 hivert /= 2.0;
1859                         }
1860                 }
1861         }
1862
1863         return (mid);
1864 }
1865 \f
1866 /*
1867  * Name:        css_affects_stemtip()
1868  *
1869  * Abstract:    Do CSS notes (if any) affect the position of the stem's tip?
1870  *
1871  * Returns:     YES or NO
1872  *
1873  * Description: This function is given a pointer to a GRPSYL.  It must be a
1874  *              note group, but can be grace or nongrace.  It may be a member
1875  *              of a beamed set, or not a member of a beamed set.  It decides
1876  *              whether the position of the tip of the stem (or where the stem
1877  *              would be for a non-stemmed note) is affected by CSS notes.
1878  */
1879
1880 int
1881 css_affects_stemtip(gs_p)
1882
1883 struct GRPSYL *gs_p;    /* starts at the given group */
1884
1885 {
1886         /*
1887          * For the single (unbeamed) group case, the position of the tip of the
1888          * stem is affected if either the CSS notes are on the stem side, or if
1889          * all the notes are CSS.
1890          */
1891         if (gs_p->beamloc == NOITEM) {
1892                 return (STEMSIDE_CSS(gs_p) || NNN(gs_p) == 0 ? YES : NO);
1893         }
1894
1895         /* CSB is never CSS */
1896         if (gs_p->beamto != CS_SAME) {
1897                 return (NO);
1898         }
1899
1900         /*
1901          * For the beamed case, either all or none of the groups can have CSS
1902          * notes on the stem side, if there are any other-staff notes at all
1903          * in the group.  This is because all the groups' stems go
1904          * the same direction, and we don't allow the beaming together of
1905          * groups where some have stemto == CS_ABOVE and others have CS_BELOW.
1906          * Theoretically a group with all CSS notes could affect the position
1907          * of the beam regardless of whether its CSS notes are stemside or not;
1908          * but we will pretend that it can't.  We'll fake things out in
1909          * setbeam().  This way, we can handle beaming and set the beam
1910          * position and good group boundaries on the beamside during the
1911          * CSSpss==NO pass.  Then the placement of "stuff" on that side will
1912          * be better.
1913          */
1914         /* if we're not at the start of the beamed set, go back to there */
1915         while (gs_p->beamloc != STARTITEM) {
1916                 gs_p = prevsimilar(gs_p);
1917         }
1918         /* check each member to see if any have stemside CSS */
1919         while (gs_p != 0) {
1920                 if (STEMSIDE_CSS(gs_p)) {
1921                         return (YES);
1922                 }
1923                 if (gs_p->beamloc == ENDITEM) {
1924                         break;
1925                 }
1926                 gs_p = nextsimilar(gs_p);
1927         }
1928         return (NO);
1929 }
1930 \f
1931 /*
1932  * Name:        css_affects_tieslurbend()
1933  *
1934  * Abstract:    Do CSS notes (if any) affect the position of this tie/slur/bend?
1935  *
1936  * Returns:     YES or NO
1937  *
1938  * Description: This function decides whether the given tie, slur, or bend is
1939  *              affected by CSS notes in any of the groups it covers.
1940  */
1941
1942 int
1943 css_affects_tieslurbend(stuff_p, mll_p)
1944
1945 struct STUFF *stuff_p;  /* the tie, slur, or bend */
1946 struct MAINLL *mll_p;   /* MLL item where this tie/slur/bend starts */
1947
1948 {
1949         struct GRPSYL *sg_p;    /* starting group of the tie/slur/bend */
1950         struct GRPSYL *eg_p;    /* starting group of the tie/slur/bend */
1951         struct NOTE *snote_p;   /* starting note of the tie/slur/bend */
1952         struct NOTE *enote_p;   /* ending note of the tie/slur/bend */
1953         int idx;                /* index of note in the group */
1954
1955
1956         /* if not cross staff stemming, don't waste time checking */
1957         if (CSSused == NO) {
1958                 return (NO);
1959         }
1960
1961         /* second half (after crossing scorefeed); was handled by first half */
1962         if (stuff_p->carryin == YES) {
1963                 return (NO);
1964         }
1965
1966         sg_p = stuff_p->beggrp_p;
1967         snote_p = stuff_p->begnote_p;
1968
1969         /* find the index of the note in the group */
1970         for (idx = 0; idx < sg_p->nnotes; idx++) {
1971                 if (&sg_p->notelist[idx] == snote_p) {
1972                         break;
1973                 }
1974         }
1975         if (idx == sg_p->nnotes) {
1976                 pfatal("can't find tied/slurred/bent note in group");
1977         }
1978
1979         /* if this starting note is CSS, return YES */
1980         if (IS_CSS_NOTE(sg_p, idx)) {
1981                 return (YES);
1982         }
1983
1984         /*
1985          * Find the end note of the tie/slur/bend.  If none, we don't care
1986          * about the end note.
1987          */
1988         eg_p = nextgrpsyl(sg_p, &mll_p);
1989         if (eg_p == 0) {
1990                 return (NO);
1991         }
1992
1993         /* find the note tied/slurred/bent to */
1994         if (stuff_p->curveno == -1) {   /* this is a tie */
1995                 enote_p = find_matching_note(eg_p, snote_p->letter,
1996                                 snote_p->octave, (char *)0);
1997         } else {                        /* this is a slur or bend */
1998                 enote_p = find_matching_note(eg_p,
1999                                 snote_p->slurtolist[stuff_p->curveno].letter,
2000                                 snote_p->slurtolist[stuff_p->curveno].octave,
2001                                 (char *)0);
2002         }
2003
2004         if (enote_p == 0) {
2005                 return (NO);
2006         }
2007
2008         /* find the index of the note in the group */
2009         for (idx = 0; idx < eg_p->nnotes; idx++) {
2010                 if (&eg_p->notelist[idx] == enote_p) {
2011                         break;
2012                 }
2013         }
2014         if (idx == eg_p->nnotes) {
2015                 pfatal("can't find tied/slurred/bent-to note in group");
2016         }
2017
2018         /* if this ending note is CSS, return YES */
2019         if (IS_CSS_NOTE(eg_p, idx)) {
2020                 return (YES);
2021         }
2022
2023         return (NO);
2024 }
2025 /*
2026  * Name:        css_affects_phrase()
2027  *
2028  * Abstract:    Do CSS notes (if any) affect the position of this phrase mark?
2029  *
2030  * Returns:     YES or NO
2031  *
2032  * Description: This function decides whether the given phrase mark is
2033  *              affected by CSS notes in any of the groups it covers.
2034  */
2035
2036 int
2037 css_affects_phrase(stuff_p, mll_p)
2038
2039 struct STUFF *stuff_p;  /* the phrase */
2040 struct MAINLL *mll_p;   /* for the group at start of phrase */
2041
2042 {
2043         struct GRPSYL *gs_p;    /* point at end group covered by phrase */
2044         int place;              /* PL_ABOVE or PL_BELOW */
2045         int staffno;            /* staff number */
2046         int vidx;               /* voice index */
2047
2048
2049         place = stuff_p->place;
2050         gs_p = stuff_p->beggrp_p;
2051         staffno = gs_p->staffno;
2052         vidx = gs_p->vno - 1;
2053         
2054         /* loop once for each group covered by the phrase */
2055         while (gs_p != 0) {
2056                 /* return YES right away if we find an affected group */
2057                 switch (gs_p->stemto) {
2058                 case CS_SAME:
2059                         break;
2060                 case CS_ABOVE:
2061                         if (place == PL_ABOVE || NNN(gs_p) == 0) {
2062                                 return (YES);
2063                         }
2064                         break;
2065                 case CS_BELOW:
2066                         if (place == PL_BELOW || NNN(gs_p) == 0) {
2067                                 return (YES);
2068                         }
2069                         break;
2070                 }
2071
2072                 /* if we've seen the last group, we are done */
2073                 if (gs_p == stuff_p->endgrp_p) {
2074                         break;
2075                 }
2076
2077                 /* find the next note group in this voice */
2078                 do {
2079                         gs_p = gs_p->next;
2080                 } while (gs_p != 0 && gs_p->grpcont != GC_NOTES);
2081
2082                 /* if we hit the end of the measure, look for next measure */
2083                 if (gs_p == 0) {
2084                         /* find the bar line */
2085                         while (mll_p != 0 && mll_p->str != S_BAR) {
2086                                 mll_p = mll_p->next;
2087                         }
2088                         /* find the matching staff in the next measure */
2089                         while (mll_p != 0 && ! (mll_p->str == S_STAFF &&
2090                                         mll_p->u.staff_p->staffno == staffno)) {
2091                                 mll_p = mll_p->next;
2092                         }
2093                         /* defensive check, should not happen */
2094                         if (mll_p == 0) {
2095                                 break;
2096                         }
2097                         /* point at the first group in new measure */
2098                         gs_p = mll_p->u.staff_p->groups_p[vidx];
2099                 }
2100         }
2101
2102         return (NO);
2103 }
2104 \f
2105 /*
2106  * Name:        nextsimilar()
2107  *
2108  * Abstract:    Return next group in a GRPSYL list that is "like" the current.
2109  *
2110  * Returns:     pointer to GRPSYL of next desired group, 0 if none
2111  *
2112  * Description: This function loop down the GRPSYL linked list from the given
2113  *              starting point.  It returns the next GRPSYL in the list that has
2114  *              the same grpcont and grpvalue as the given one, or 0 if none.
2115  */
2116
2117 struct GRPSYL *
2118 nextsimilar(gs_p)
2119
2120 struct GRPSYL *gs_p;    /* current group */
2121
2122 {
2123         int curvalue;
2124         int curcont;
2125
2126         curvalue = gs_p->grpvalue;
2127         curcont = gs_p->grpcont;
2128         gs_p = gs_p->next;
2129         while (gs_p != 0 &&
2130               (gs_p->grpvalue != curvalue || gs_p->grpcont != curcont)) {
2131                 gs_p = gs_p->next;
2132         }
2133         return (gs_p);
2134 }
2135 \f
2136 /*
2137  * Name:        prevsimilar()
2138  *
2139  * Abstract:    Return prev group in a GRPSYL list that is "like" the current.
2140  *
2141  * Returns:     pointer to GRPSYL of previous desired group, 0 if none
2142  *
2143  * Description: This function loops down the GRPSYL linked list from the given
2144  *              starting point.  It returns the prev GRPSYL in the list that has
2145  *              the same grpcont and grpvalue as the given one, or 0 if none.
2146  */
2147
2148 struct GRPSYL *
2149 prevsimilar(gs_p)
2150
2151 struct GRPSYL *gs_p;    /* current group */
2152
2153 {
2154         int curvalue;
2155         int curcont;
2156
2157         curvalue = gs_p->grpvalue;
2158         curcont = gs_p->grpcont;
2159         gs_p = gs_p->prev;
2160         while (gs_p != 0 &&
2161               (gs_p->grpvalue != curvalue || gs_p->grpcont != curcont)) {
2162                 gs_p = gs_p->prev;
2163         }
2164         return (gs_p);
2165 }
2166 \f
2167 /*
2168  * Name:        gs2ch()
2169  *
2170  * Abstract:    Given a GRPSYL and its staff's MLL, find chord for that time.
2171  *
2172  * Returns:     pointer to CHORD structure
2173  *
2174  * Description: This function is given a GRPSYL and the MLL structure for the
2175  *              GRPSYL's staff.  It finds the CHORD structure that heads the
2176  *              list of GRPSYLs occurring at that time in that measure.  Note
2177  *              that if the given GRPSYL is grace, it won't actually occur in
2178  *              that linked list of GRPSYLs; but in that case the following
2179  *              non-grace GRPSYL will.
2180  */
2181
2182 struct CHORD *
2183 gs2ch(mll_p, gs_p)
2184
2185 struct MAINLL *mll_p;   /* the MLL for the given GRPSYL */
2186 struct GRPSYL *gs_p;    /* the given GRPSYL */
2187
2188 {
2189         struct CHORD *ch_p;             /* loop through chords */
2190         struct GRPSYL *gs2_p;           /* point along a GRPSYL list */
2191         RATIONAL time;                  /* time offset where our group is */
2192
2193
2194         /* find chord headcell for this measure */
2195         while (mll_p != 0 && mll_p->str == S_STAFF) {
2196                 mll_p = mll_p->prev;
2197         }
2198         if (mll_p == 0 || mll_p->str != S_CHHEAD) {
2199                 pfatal("missing chord head cell in gs2ch");
2200         }
2201
2202         /* find time offset of our group by summing all previous groups */
2203         time = Zero;
2204         for (gs2_p = gs_p->prev; gs2_p != 0; gs2_p = gs2_p->prev) {
2205                 time = radd(time, gs2_p->fulltime);
2206         }
2207
2208         /*
2209          * Find the chord that contains our group (or, if we are a grace group,
2210          * the following normal group).
2211          */
2212         for (ch_p = mll_p->u.chhead_p->ch_p;
2213                         ch_p != 0 && NE(ch_p->starttime, time);
2214                         ch_p = ch_p->ch_p) {
2215                 ;
2216         }
2217         if (ch_p == 0) {
2218                 pfatal("can't find chord in gs2ch");
2219         }
2220
2221         return (ch_p);
2222 }
2223 \f
2224 /*
2225  * Name:        stemroom()
2226  *
2227  * Abstract:    Try to find how much room a "wrong way" stem needs.
2228  *
2229  * Returns:     The room needed, measured in stepsizes.
2230  *
2231  * Description: This function is given a nongrace note group whose stem has
2232  *              been forced the wrong way (down for the top group or up for the
2233  *              bottom group) despite the other voice being nonspace.  It tries
2234  *              to find how long the stem will be so that we can decide whether
2235  *              the groups need to be horizontally offset.  It works well for
2236  *              nonbeamed groups, but for beamed groups it can only guess.  It
2237  *              is to be used in places where we need to know the stem length
2238  *              (to the extent possible) even though beamstem.c hasn't run yet.
2239  *
2240  *              WARNING:  This code is similar to the nongrace section of
2241  *              proclist() in beamstem.c.  If you change one, you probably
2242  *              will need to change the other.
2243  */
2244
2245 double
2246 stemroom(gs_p)
2247
2248 struct GRPSYL *gs_p;            /* the group in question */
2249
2250 {
2251         float room;             /* the answer, in stepsizes */
2252         int bf;                 /* number of beams/flags */
2253
2254
2255         /*
2256          * If user specified stem length, use that.
2257          */
2258         if (IS_STEMLEN_KNOWN(gs_p->stemlen)) {
2259                 return (gs_p->stemlen / STEPSIZE);
2260         }
2261
2262         /*
2263          * If this group is part of a beamed set, there is no way to know how
2264          * long the stem will be, since the beaming hasn't been done yet, and
2265          * can't be done until all horizontal placement has been done.  So
2266          * return the default stem length and hope for the best.
2267          */
2268         if (gs_p->beamloc != NOITEM) {
2269                 return (DEFSTEMLEN);
2270         }
2271
2272         /*
2273          * Only half notes and shorter have stems, but whole and double
2274          * whole notes still need to have a pseudo stem length set if
2275          * alternation beams are to be drawn between two neighboring
2276          * groups, or the group has slashes.
2277          */
2278         if (gs_p->basictime <= 1 && gs_p->slash_alt == 0) {
2279                 /* no (pseudo)stem */
2280                 return (0.0);
2281         }
2282
2283         /* find default stemlen for this voice */
2284         room = vvpath(gs_p->staffno, gs_p->vno, STEMLEN)->stemlen;
2285         if (room == 0.0) {
2286                 return (0.0);
2287         }
2288
2289         /* if small notes, reduce this default */
2290         room *= (allsmall(gs_p, gs_p) == YES ? SM_STEMFACTOR : 1.0);
2291
2292         /* add more, if needed, for flags/beams/slashes/alternations */
2293         if (gs_p->basictime >= 8) {
2294                 bf = drmo(gs_p->basictime) - 2; /* no. of beams/flags*/
2295         } else {
2296                 bf = 0;                 /* none on quarter or longer */
2297         }
2298         bf += abs(gs_p->slash_alt);     /* slashes or alternations */
2299         if (gs_p->slash_alt > 0 && gs_p->basictime >= 16) {
2300                 bf++;   /* slashes need an extra one if 16, 32, ... */
2301         }
2302         if (bf > 2) {
2303                 room += (bf - 2) * FLAGSEP / STEPSIZE;
2304         }
2305
2306         /*
2307          * If the note may have flag(s), is stem up, and has dot(s), we must
2308          * prevent the flag(s) from hitting the dot(s), by lengthening the stem.
2309          */
2310         if (gs_p->basictime >= 8 && gs_p->stemdir == UP && gs_p->dots != 0) {
2311                 if (gs_p->notelist[0].stepsup % 2 == 0) {
2312                         /* note is on a line */
2313                         if (gs_p->basictime == 8) {
2314                                 room += 1.0;
2315                         } else {
2316                                 room += 2.0;
2317                         }
2318                 } else {
2319                         /* note is on a space */
2320                         if (gs_p->basictime > 8) {
2321                                 room += 1.0;
2322                         }
2323                 }
2324         }
2325
2326         return (room);
2327 }