1 /* Copyright (c) 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004,
2 * 2005, 2006 by Arkkra Enterprises */
3 /* All rights reserved */
7 * Description: This file contains utility functions belonging to the placement
8 * phase. Some of them are also used by other phases.
15 static int phrase_tieslur_note P((struct GRPSYL *gs_p, int nidx, int side,
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,
21 static RATIONAL righttime P((double count, struct GRPSYL *firstgs_p,
25 * Name: nextnongrace()
27 * Abstract: Return next nongrace group in a GRPSYL list.
29 * Returns: pointer to GRPSYL of next nongrace group, 0 if none
31 * Description: This function loops down the GRPSYL linked list from the given
32 * starting point. It returns the next nongrace GRPSYL, or 0
39 struct GRPSYL *gs_p; /* current group */
43 while (gs_p != 0 && gs_p->grpvalue == GV_ZERO)
49 * Name: prevnongrace()
51 * Abstract: Return previous nongrace group in a GRPSYL list.
53 * Returns: pointer to GRPSYL of previous nongrace group, 0 if none
55 * Description: This function loop up the GRPSYL linked list from the given
56 * starting point. It returns the previous nongrace GRPSYL, or 0
63 struct GRPSYL *gs_p; /* current group */
67 while (gs_p != 0 && gs_p->grpvalue == GV_ZERO)
73 * Name: nextglobnongrace()
75 * Abstract: Return next nongrace group in this voice.
77 * Returns: pointer to GRPSYL of next nongrace group, 0 if none
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.
87 nextglobnongrace(gs_p, mll_p_p)
89 struct GRPSYL *gs_p; /* current group */
90 struct MAINLL **mll_p_p; /* MLL structure it is hanging off of */
94 gs_p = nextgrpsyl(gs_p, mll_p_p);
95 } while (gs_p != 0 && gs_p->grpvalue == GV_ZERO);
100 * Name: prevglobnongrace()
102 * Abstract: Return previous nongrace group in this voice.
104 * Returns: pointer to GRPSYL of previous nongrace group, 0 if none
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.
115 prevglobnongrace(gs_p, mll_p_p)
117 struct GRPSYL *gs_p; /* current group */
118 struct MAINLL **mll_p_p; /* MLL structure it is hanging off of */
122 gs_p = prevgrpsyl(gs_p, mll_p_p);
123 } while (gs_p != 0 && gs_p->grpvalue == GV_ZERO);
130 * Abstract: Detect rightmost one.
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.
147 for (n = 0; n < 8 * sizeof(int); n++) {
148 if ( (num & (1 << n)) != 0 )
151 pfatal("0 was passed to drmo");
152 return (0); /* dead code, but keeps lint happy */
158 * Abstract: How much tie/slur padding is needed after this group?
160 * Returns: Padding in inches.
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.
170 tieslurpad(staff_p, gs_p)
172 struct STAFF *staff_p; /* the staff the group is connected to */
173 struct GRPSYL *gs_p; /* the group after which padding may occur */
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 */
188 /* syllables can't have ties or slurs */
189 if (gs_p->grpsyl != GS_GROUP)
192 /* rests and spaces can't have ties or slurs */
193 if (gs_p->grpcont != GC_NOTES)
196 /* if last group in measure, don't need any more space */
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
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);
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 */
218 that_p = 0; /* we are voice 3, ignore other voices */
220 if (that_p == 0 || hasspace(that_p, starttime,
221 radd(starttime, gs_p->fulltime)))
226 pad = 0; /* start with no padding */
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.
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);
251 for (s = 0; s < note_p->nslurto; s++) {
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
257 if (IS_NOWHERE(note_p->slurtolist[s].octave))
258 continue; /* from nowhere */
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
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);
274 pad = MAX(pad, stepdiff <= 3 ? 0 :
275 (stepdiff - 3) * STEPSIZE / 2);
280 return (pad); /* max padding needed by any pair of notes */
284 * Name: phrase_tieslur_note()
286 * Abstract: Is the given note the end note and eligible for "new" tie/slur?
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).
296 phrase_tieslur_note(gs_p, nidx, side, interfere)
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?*/
304 /* check for each bad condition, returning NO if it exists */
306 /* inner note of a group */
307 if (nidx != 0 && nidx != gs_p->nnotes - 1)
310 /* bottom note of voice 1 and other voice interferes */
311 if (gs_p->vno == 1 && nidx == gs_p->nnotes - 1 && interfere)
314 /* top note of voice 2 and other voice interferes */
315 if (gs_p->vno == 2 && nidx == 0 && interfere)
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)
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)
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)
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)
344 * Name: tied_to_nidx()
346 * Abstract: Return the note index of the note the given note is tied to.
348 * Returns: index into gs_p->next->notelist
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.
357 tied_to_nidx(gs_p, nidx)
359 struct GRPSYL *gs_p; /* point at note's group */
360 int nidx; /* index to this note in notelist */
363 struct NOTE *nl_ptr; /* ptr to next group's notelist */
367 nl_ptr = gs_p->next->notelist;
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)
375 pfatal("tied_to_nidx: can't find note tied to");
376 return (0); /* to keep lint happy */
380 * Name: slurred_to_nidx()
382 * Abstract: Return the note index of the note the given note is slurred to.
384 * Returns: index into gs_p->next->notelist
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.
393 slurred_to_nidx(gs_p, nidx, sidx)
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 */
400 struct NOTE *nl_ptr; /* ptr to next group's notelist */
404 nl_ptr = gs_p->next->notelist;
406 for (n = 0; n < gs_p->next->nnotes; n++) {
407 if (gs_p->notelist[nidx].slurtolist[sidx].letter ==
409 gs_p->notelist[nidx].slurtolist[sidx].octave ==
414 pfatal("slurred_to_nidx: can't find note slurred to");
415 return (0); /* to keep lint happy */
421 * Abstract: Finds out if the given voice has space during given time.
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".
436 hasspace(gs_p, vtime, vtime2)
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 */
442 RATIONAL t; /* accumulate time */
443 int oldcont; /* content of previous group */
446 /* "no linked list exists" counts as all spaces */
450 oldcont = GC_SPACE; /* prevent useless 'used before set' warning */
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)
456 t = radd(t, gs_p->fulltime);
457 oldcont = gs_p->grpcont;
460 if (GT(t, vtime) && oldcont != GC_SPACE)
463 for ( ; gs_p != 0 && LT(t, vtime2); gs_p = gs_p->next) {
464 if (gs_p->grpvalue == GV_ZERO)
466 if (gs_p->grpcont != GC_SPACE)
468 t = radd(t, gs_p->fulltime);
475 * Name: closestgroup()
477 * Abstract: Find closest nongrace group in this voice to given time value.
479 * Returns: pointer to the closest nongrace GRPSYL
481 * Description: This function finds the GRPSYL in the given linked list that is
482 * closest, timewise, to the given count number, ignoring grace
487 closestgroup(count, firstgs_p, timeden)
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 */
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 */
501 /* skip over any initial grace groups */
502 if (firstgs_p->grpvalue == GV_ZERO)
503 firstgs_p = nextnongrace(firstgs_p);
505 /* if at or before the first count, it's closest to first group */
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;
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.
521 for (ogs_p = firstgs_p, gs_p = nextnongrace(ogs_p); gs_p != 0;
522 ogs_p = gs_p, gs_p = nextnongrace(gs_p)) {
524 tottime = radd(tottime, ogs_p->fulltime);
525 if (GE(tottime, reqtime)) {
526 if (GT( rsub(reqtime,otottime), rsub(tottime,reqtime) ))
533 /* requested time is after last group; return last group */
538 * Name: chkallspace()
540 * Abstract: Check if voice is all spaces for the voice this stuff is on.
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.)
557 chkallspace(msbeg_p, stuff_p, vno)
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 */
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 */
572 * Find what measure this stuff ends in. Along the way, keep
573 * track of the time signature denominator, in case it changes.
575 msend_p = getendstuff(msbeg_p, stuff_p, &timeden);
578 * If we hit a multirest, bail out, arbitrarily returning NO. This
579 * stuff will be thrown away later anyway.
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.
589 if (msend_p->u.staff_p->groups_p[1] == NULL) {
590 return (vno == 1 ? YES : NO);
594 * Find time values that are sure to contain the stuff. Take the
595 * outermost values of the two voices.
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))
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))
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.
617 if (msbeg_p == msend_p && EQ(begtime, endtime))
618 endtime = radd(endtime, tiny);
620 return (allspace(vno, msbeg_p, begtime, msend_p, endtime));
626 * Abstract: Finds out if the given voice has space for the given time.
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.
639 allspace(vno, msbeg_p, begtime, msend_p, endtime)
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 */
648 struct MAINLL *mainll_p; /* point along MLL */
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],
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.
665 if (hasspace(msbeg_p->u.staff_p->groups_p[vno], begtime, Maxtime) == NO)
668 staffno = msbeg_p->u.staff_p->staffno;
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) {
674 /* skip everything but STAFFs for our staff number */
675 if (mainll_p->str != S_STAFF ||
676 mainll_p->u.staff_p->staffno != staffno)
679 if (hasspace(mainll_p->u.staff_p->groups_p[vno], Zero, Maxtime)
685 pfatal("bug found in allspace");
687 /* the result is now determined by the last measure */
688 return (hasspace(msend_p->u.staff_p->groups_p[vno], Zero, endtime));
692 * Name: getendstuff()
694 * Abstract: Find staff and time signature denominator for end of a stuff.
696 * Returns: pointer to MLL structure for staff containing end of stuff, or 0
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
707 getendstuff(mainll_p, stuff_p, timeden_p)
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 */
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 */
720 /* bail out if multirest */
721 if (mainll_p->u.staff_p->groups_p[0]->basictime < -1)
724 timenum = Score.timenum; /* init to current time sig numerator*/
725 *timeden_p = Score.timeden; /* init to current time sig denom */
727 /* if stuff doesn't cross any bar lines, we can return right away */
728 if (stuff_p->end.bars == 0)
731 mst_p = mainll_p; /* remember last staff of this number */
733 staffno = mainll_p->u.staff_p->staffno;
736 * Count past the right number of bar lines, keeping the time sig
737 * denominator up to date.
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) {
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;
750 /* bail out if multirest encountered */
751 if (mainll_p->str == S_STAFF && mainll_p->u.staff_p->
752 groups_p[0]->basictime < -1)
755 /* remember last staff of this number */
756 if (mainll_p->str == S_STAFF && mainll_p->u.staff_p->
760 /* if end of song, set to last bar line and return this staff*/
762 stuff_p->end.count = timenum + 1;
768 * mainll_p points at the bar line preceding the place where the stuff
769 * ends. Continue forward to find the correct STAFF.
771 for (mainll_p = mainll_p->next ;
772 mainll_p != 0 && mainll_p->str != S_BAR;
773 mainll_p = mainll_p->next) {
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;
779 if (mainll_p->str == S_STAFF &&
780 mainll_p->u.staff_p->staffno == staffno)
784 /* if end of song, set to last bar line and return this staff */
786 stuff_p->end.count = timenum + 1;
787 return (mst_p); /* hit end of song, return last meas */
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)
800 * Abstract: Find time value of the nongrace group left of the given count.
802 * Returns: time value into measure
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.
811 lefttime(count, firstgs_p, timeden)
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 */
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 */
825 /* skip over any initial grace groups */
826 if (firstgs_p->grpvalue == GV_ZERO)
827 firstgs_p = nextnongrace(firstgs_p);
829 /* if at or before the first count, have to use first group */
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
839 reqtime.n = 2 * MAXBASICTIME * (count - 1) + 0.5 + 1.0;
840 reqtime.d = 2 * MAXBASICTIME * timeden;
844 * Loop through this voice accumulating time values. As soon as we
845 * equal or exceed the requested time value, return the previous
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)) {
852 tottime = radd(tottime, ogs_p->fulltime);
853 if (GE(tottime, reqtime))
857 /* requested time is after last group; return time of last group */
864 * Abstract: Find time value of the nongrace group right of the given count.
866 * Returns: time value into measure
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.
876 righttime(count, firstgs_p, timeden)
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 */
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 */
889 /* skip over any initial grace groups */
890 if (firstgs_p->grpvalue == GV_ZERO)
891 firstgs_p = nextnongrace(firstgs_p);
893 /* if at or before the first count, use first group */
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
903 reqtime.n = 2 * MAXBASICTIME * (count - 1) + 0.5 - 1.0;
904 reqtime.d = 2 * MAXBASICTIME * timeden;
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.
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))
920 /* requested time is after last group; but must return last group */
927 * Abstract: Find the dimensions of a note's accidental.
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.
941 accdimen(note_p, ascent_p, descent_p, width_p)
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 */
949 char accchar; /* accidental character number */
950 int size; /* which size of character */
951 float halfhigh; /* half the height of a parenthesis */
954 if (note_p->accidental == '\0') {
958 if (descent_p != 0) {
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);
971 /* get the requested dimensions of this accidental */
973 *ascent_p = ascent(FONT_MUSIC, size, accchar);
975 if (descent_p != 0) {
976 *descent_p = descent(FONT_MUSIC, size, accchar);
979 *width_p = width(FONT_MUSIC, size, accchar);
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.
987 if (note_p->acc_has_paren) {
989 *width_p += 2 * width(FONT_TR, size, '(');
991 halfhigh = height(FONT_TR, size, '(') / 2.0;
992 if (ascent_p != 0 && halfhigh > *ascent_p) {
993 *ascent_p = halfhigh;
995 if (descent_p != 0 && halfhigh > *descent_p) {
996 *descent_p = halfhigh;
1002 * Name: staffvertspace()
1004 * Abstract: Find the minimum amount of vertical space a staff should have.
1006 * Returns: the amount of vertical distance in inches
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.
1020 int s; /* staff number */
1023 float space; /* the answer */
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.
1030 space = (svpath(s, STAFFLINES)->stafflines - 1) * 2 * STEPSIZE;
1031 if (is_tab_staff(s))
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));
1039 * Name: halfstaffhi()
1041 * Abstract: Find half of the staff height.
1043 * Returns: half the staff height in inches
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.
1057 int s; /* staff number */
1060 float space; /* the answer */
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.
1068 space = (svpath(s, STAFFLINES)->stafflines - 1) * STEPSIZE;
1069 if (is_tab_staff(s))
1072 /* but don't ever return less than one (scaled) stepsize */
1073 return (MAX(space, STEPSIZE) * svpath(s, STAFFSCALE)->staffscale);
1079 * Abstract: Convert a bend distance to rational.
1081 * Returns: the rational number answer; 0/1 if null bend or no bend
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.
1090 struct NOTE *note_p;
1096 if (note_p->BEND == 0)
1099 answer.d = BENDDEN(*note_p);
1100 answer.n = BENDNUM(*note_p) + BENDINT(*note_p) * answer.d;
1109 * Abstract: Find horizontal boundary of note and associated things.
1111 * Returns: the RE or RW
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
1117 * NOTE: This function takes staffscale into account. The SSVs
1118 * need not be up to date, but Staffscale and Stdpad must be set.
1122 notehorz(gs_p, note_p, coord)
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 */
1129 int s; /* index into slurtolist */
1130 double h; /* the answer */
1134 if (note_p->note_has_paren == YES &&
1135 ! is_tab_staff(gs_p->staffno)) {
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.
1143 h = note_p->erparen;
1146 * If non-tablature and there are dots, start from the
1147 * first dot. Otherwise start from the note.
1149 if (is_tab_staff(gs_p->staffno) == NO &&
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));
1157 h = note_p->c[RE] + Stdpad;
1162 * If this note has a slur to nowhere (and there can be at most
1163 * one such), include its length.
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);
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) */
1185 /* the note head itself, with padding */
1186 h = note_p->c[RW] - Stdpad;
1190 * If this note has a slur from nowhere (and there can be at
1191 * most one such), include its length.
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);
1208 * Abstract: Do the given groups (of notes) consist entirely of small notes?
1210 * Returns: YES or NO
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.
1220 allsmall(gs1_p, gs2_p)
1222 struct GRPSYL *gs1_p; /* starting group */
1223 struct GRPSYL *gs2_p; /* ending group (may be same as starting group) */
1226 struct GRPSYL *gs_p; /* point along the list */
1227 int n; /* index into notelist */
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)
1240 return (YES); /* everything must have been small */
1244 * Name: finalstemadjust()
1246 * Abstract: Make final adjustments to the stem length.
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.
1259 finalstemadjust(gs_p)
1261 struct GRPSYL *gs_p; /* group whose stemlen should be adjusted */
1264 float stepdiff; /* distance between outer notes in steps */
1267 /* if it is negative (note on wrong side of beam), zap it */
1268 if (gs_p->stemlen < 0)
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;
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.
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);
1287 * Name: getstemshift()
1289 * Abstract: Find how far a stem is from the group's X coordinate.
1291 * Returns: the distance in inches
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.
1301 struct GRPSYL *gs_p; /* group whose stemlen should be adjusted */
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);
1310 * Name: vscheme_voices()
1312 * Abstract: Given a vscheme, how many voices are in it?
1314 * Returns: number of voices
1316 * Description: This function is given one of the valid vschemes, and it
1317 * returns the number of voices that vscheme allows.
1321 vscheme_voices(vscheme)
1323 int vscheme; /* the given vscheme */
1339 pfatal("invalid vscheme in vscheme_voices()");
1346 * Name: chmgrp2staffm()
1348 * Abstract: Given a chord and group, find the group's staff.
1350 * Returns: pointer to staff's MLL item
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.
1359 chmgrp2staffm(mll_p, gs_p)
1361 struct MAINLL *mll_p; /* starts as MLL for the chord */
1362 struct GRPSYL *gs_p; /* starts as GRPSYL the given group */
1365 /* find the first group in this measure */
1366 for ( ; gs_p->prev != 0; gs_p = gs_p->prev)
1369 /* find the staff that it belongs to */
1370 for ( ; mll_p != 0; mll_p = mll_p->next) {
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))
1379 pfatal("can't find staff in chmgrp2staffm");
1387 * Abstract: Shift a GRPSYL's relative horizontal coords.
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.
1397 shiftgs(gs_p, shift)
1399 struct GRPSYL *gs_p; /* the main GRPSYL */
1403 struct GRPSYL *ggs_p; /* point at a grace group */
1406 gs_p->c[RX] += shift;
1407 gs_p->c[RW] += shift;
1408 gs_p->c[RE] += shift;
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;
1420 * Name: nearestline()
1422 * Abstract: Round a vertical offset to the nearest staff line.
1424 * Returns: the resulting offset
1426 * Description: This function rounds its parameter off to a multiple of 2
1428 * NOTE: This function takes staffscale into account. The SSVs
1429 * need not be up to date, but Stepsize must be set.
1435 double offset; /* offset from center staff line */
1439 offset /= (2 * Stepsize);
1440 offset = (int)(offset + 0.5);
1441 offset *= (2 * Stepsize);
1444 offset /= (2 * Stepsize);
1445 offset = (int)(offset + 0.5);
1446 offset *= (2 * Stepsize);
1456 * Abstract: Verify horizontal offsets are not in conflict.
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
1468 struct GRPSYL *g_p[]; /* array of pointers to two groups */
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)
1475 /* can't both be "+" or both be "-" */
1476 if (g_p[0]->ho_usage == g_p[1]->ho_usage) {
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 ? '-' :'+');
1483 g_p[0]->ho_usage = HO_NONE;
1484 g_p[1]->ho_usage = HO_NONE;
1491 * Abstract: Adjust the slope of a beam.
1493 * Returns: the new slope
1495 * Description: This function is given the slope of a beam as determined by
1496 * linear regression. It adjusts it according to the "beamslope"
1501 adjslope(g_p, oldslope, betweencsb)
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? */
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 */
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;
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
1524 if (betweencsb == YES)
1527 /* new angle = old angle * beamfact */
1528 newangle = (atan(oldslope) * 180.0 / PI) * beamfact;
1530 /* force it to stay within the limit */
1531 if (newangle > beammax)
1533 else if (newangle < -beammax)
1534 newangle = -beammax;
1536 /* return as slope */
1537 return (tan(newangle * PI / 180.0));
1541 * Name: curve_y_at_x()
1543 * Abstract: Given a curve and an X value, return the Y value there.
1545 * Returns: the Y value
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.
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.
1560 * The function assumes that the curve points will be connected by
1561 * cubic curves, according to the algorithm in calccurve() and
1566 curve_y_at_x(first_p, x)
1568 struct CRVLIST *first_p; /* left endpoint of curve */
1569 double x; /* X coord at which we need Y */
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 */
1585 * If the first point of the curve is at or already beyond the given x,
1586 * return the first point's y.
1588 if (first_p->x >= x) {
1589 return (first_p->y);
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);
1598 /* if x is within this interval, break out */
1599 if (left_p->x < x && x < right_p->x) {
1603 /* if this happens, x is beyond the last point, so use last point's y */
1604 if (left_p->next == 0) {
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
1619 rotangle = findcubic(left_p, right_p, &a, &b, &c);
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.
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;
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.
1641 if (rotangle < 0.0) {
1642 lineslope = tan(PI / 2.0 + rotangle);
1644 lineslope = tan(-PI / 2.0 + rotangle);
1648 * In the real coord system, the vertical line hits (x, 0). Find this
1649 * point in the translated/rotated system.
1651 /* first translate */
1652 tranx = x - left_p->x;
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;
1660 /* find Y intercept in the translated/rotated system */
1661 intercept = pointy - lineslope * pointx;
1664 * Now, in the tran/rot coord system, we need to find the intersection
1666 * y = lineslope * x + intercept
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
1672 * a * x^3 + b * x^2 + (c - lineslope) * x - intercept = 0
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;
1682 /* rotate backwards, getting Y value */
1683 trany = pointy * cos_rotangle - pointx * sin_rotangle;
1685 /* translate back to the original coord system */
1686 y = trany + left_p->y;
1694 * Abstract: Given neighboring curve points, find cubic and rotation angle.
1696 * Returns: angle from new coord system's X axis to old system's (radians)
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
1707 findcubic(left_p, right_p, a_p, b_p, c_p)
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 */
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 */
1722 langle = rangle = 0.0; /* for lint */
1724 /* get angle of this segment */
1725 thisang = atan((right_p->y - left_p->y) / (right_p->x - left_p->x));
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;
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;
1741 if (left_p->prev == 0) {
1742 /* no previous segment; use same angle as on the right */
1745 if (right_p->next == 0) {
1746 /* no next segment; use same angle as on the left */
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));
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
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.
1767 /* find the slope of the tangent lines at the first & second points */
1768 lslope = -tan(langle);
1769 rslope = tan(rangle);
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;
1780 * Name: solvecubic()
1782 * Abstract: Find a solution to a cubic equation within a given interval.
1784 * Returns: the solution
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.
1796 solvecubic(a, b, c, d, lo, hi, thresh)
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 */
1802 #define FUNC(x) (((a * x + b) * x + c) * x + d)
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 */
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.
1820 if (lovert * hivert > 0.0) {
1821 if (fabs(lovert) < thresh)
1823 if (fabs(hivert) < thresh)
1825 pfatal("solvecubic was called with an invalid interval");
1831 for (n = 0; n < 20 && hi - lo > thresh; n++) {
1832 oldmidvert = midvert;
1835 * Find a point somewhere in the interval by passing a segment
1836 * through (lo, lovert) and (hi, hivert) and seeing where it
1839 mid = (lovert * hi - hivert * lo) / (lovert - hivert);
1840 midvert = FUNC(mid);
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.
1848 if ((lovert > 0.0) != (midvert > 0.0)) {
1851 if ((midvert > 0.0) == (oldmidvert > 0.0)) {
1857 if ((midvert > 0.0) == (oldmidvert > 0.0)) {
1867 * Name: css_affects_stemtip()
1869 * Abstract: Do CSS notes (if any) affect the position of the stem's tip?
1871 * Returns: YES or NO
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.
1881 css_affects_stemtip(gs_p)
1883 struct GRPSYL *gs_p; /* starts at the given group */
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.
1891 if (gs_p->beamloc == NOITEM) {
1892 return (STEMSIDE_CSS(gs_p) || NNN(gs_p) == 0 ? YES : NO);
1895 /* CSB is never CSS */
1896 if (gs_p->beamto != CS_SAME) {
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
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);
1918 /* check each member to see if any have stemside CSS */
1920 if (STEMSIDE_CSS(gs_p)) {
1923 if (gs_p->beamloc == ENDITEM) {
1926 gs_p = nextsimilar(gs_p);
1932 * Name: css_affects_tieslurbend()
1934 * Abstract: Do CSS notes (if any) affect the position of this tie/slur/bend?
1936 * Returns: YES or NO
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.
1943 css_affects_tieslurbend(stuff_p, mll_p)
1945 struct STUFF *stuff_p; /* the tie, slur, or bend */
1946 struct MAINLL *mll_p; /* MLL item where this tie/slur/bend starts */
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 */
1956 /* if not cross staff stemming, don't waste time checking */
1957 if (CSSused == NO) {
1961 /* second half (after crossing scorefeed); was handled by first half */
1962 if (stuff_p->carryin == YES) {
1966 sg_p = stuff_p->beggrp_p;
1967 snote_p = stuff_p->begnote_p;
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) {
1975 if (idx == sg_p->nnotes) {
1976 pfatal("can't find tied/slurred/bent note in group");
1979 /* if this starting note is CSS, return YES */
1980 if (IS_CSS_NOTE(sg_p, idx)) {
1985 * Find the end note of the tie/slur/bend. If none, we don't care
1986 * about the end note.
1988 eg_p = nextgrpsyl(sg_p, &mll_p);
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,
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) {
2014 if (idx == eg_p->nnotes) {
2015 pfatal("can't find tied/slurred/bent-to note in group");
2018 /* if this ending note is CSS, return YES */
2019 if (IS_CSS_NOTE(eg_p, idx)) {
2026 * Name: css_affects_phrase()
2028 * Abstract: Do CSS notes (if any) affect the position of this phrase mark?
2030 * Returns: YES or NO
2032 * Description: This function decides whether the given phrase mark is
2033 * affected by CSS notes in any of the groups it covers.
2037 css_affects_phrase(stuff_p, mll_p)
2039 struct STUFF *stuff_p; /* the phrase */
2040 struct MAINLL *mll_p; /* for the group at start of phrase */
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 */
2049 place = stuff_p->place;
2050 gs_p = stuff_p->beggrp_p;
2051 staffno = gs_p->staffno;
2052 vidx = gs_p->vno - 1;
2054 /* loop once for each group covered by the phrase */
2056 /* return YES right away if we find an affected group */
2057 switch (gs_p->stemto) {
2061 if (place == PL_ABOVE || NNN(gs_p) == 0) {
2066 if (place == PL_BELOW || NNN(gs_p) == 0) {
2072 /* if we've seen the last group, we are done */
2073 if (gs_p == stuff_p->endgrp_p) {
2077 /* find the next note group in this voice */
2080 } while (gs_p != 0 && gs_p->grpcont != GC_NOTES);
2082 /* if we hit the end of the measure, look for next measure */
2084 /* find the bar line */
2085 while (mll_p != 0 && mll_p->str != S_BAR) {
2086 mll_p = mll_p->next;
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;
2093 /* defensive check, should not happen */
2097 /* point at the first group in new measure */
2098 gs_p = mll_p->u.staff_p->groups_p[vidx];
2106 * Name: nextsimilar()
2108 * Abstract: Return next group in a GRPSYL list that is "like" the current.
2110 * Returns: pointer to GRPSYL of next desired group, 0 if none
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.
2120 struct GRPSYL *gs_p; /* current group */
2126 curvalue = gs_p->grpvalue;
2127 curcont = gs_p->grpcont;
2130 (gs_p->grpvalue != curvalue || gs_p->grpcont != curcont)) {
2137 * Name: prevsimilar()
2139 * Abstract: Return prev group in a GRPSYL list that is "like" the current.
2141 * Returns: pointer to GRPSYL of previous desired group, 0 if none
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.
2151 struct GRPSYL *gs_p; /* current group */
2157 curvalue = gs_p->grpvalue;
2158 curcont = gs_p->grpcont;
2161 (gs_p->grpvalue != curvalue || gs_p->grpcont != curcont)) {
2170 * Abstract: Given a GRPSYL and its staff's MLL, find chord for that time.
2172 * Returns: pointer to CHORD structure
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.
2185 struct MAINLL *mll_p; /* the MLL for the given GRPSYL */
2186 struct GRPSYL *gs_p; /* the given GRPSYL */
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 */
2194 /* find chord headcell for this measure */
2195 while (mll_p != 0 && mll_p->str == S_STAFF) {
2196 mll_p = mll_p->prev;
2198 if (mll_p == 0 || mll_p->str != S_CHHEAD) {
2199 pfatal("missing chord head cell in gs2ch");
2202 /* find time offset of our group by summing all previous groups */
2204 for (gs2_p = gs_p->prev; gs2_p != 0; gs2_p = gs2_p->prev) {
2205 time = radd(time, gs2_p->fulltime);
2209 * Find the chord that contains our group (or, if we are a grace group,
2210 * the following normal group).
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) {
2218 pfatal("can't find chord in gs2ch");
2227 * Abstract: Try to find how much room a "wrong way" stem needs.
2229 * Returns: The room needed, measured in stepsizes.
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.
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.
2248 struct GRPSYL *gs_p; /* the group in question */
2251 float room; /* the answer, in stepsizes */
2252 int bf; /* number of beams/flags */
2256 * If user specified stem length, use that.
2258 if (IS_STEMLEN_KNOWN(gs_p->stemlen)) {
2259 return (gs_p->stemlen / STEPSIZE);
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.
2268 if (gs_p->beamloc != NOITEM) {
2269 return (DEFSTEMLEN);
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.
2278 if (gs_p->basictime <= 1 && gs_p->slash_alt == 0) {
2279 /* no (pseudo)stem */
2283 /* find default stemlen for this voice */
2284 room = vvpath(gs_p->staffno, gs_p->vno, STEMLEN)->stemlen;
2289 /* if small notes, reduce this default */
2290 room *= (allsmall(gs_p, gs_p) == YES ? SM_STEMFACTOR : 1.0);
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*/
2296 bf = 0; /* none on quarter or longer */
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, ... */
2303 room += (bf - 2) * FLAGSEP / STEPSIZE;
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.
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) {
2319 /* note is on a space */
2320 if (gs_p->basictime > 8) {