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) {