1 /* Copyright (c) 1995, 1996, 1997, 1998, 2000, 2001, 2003, 2004, 2005, 2006
2 * by Arkkra Enterprises */
3 /* All rights reserved */
7 * Description: This file contains functions for setting relative vertical
8 * locations of notes. It also sets relative vertical locations
9 * of the groups that contain notes, considering only the notes.
10 * It also sets the directions of stems.
17 static void locnotes P((void));
18 static void locllnotes P((struct MAINLL *mll_p, int v,
19 struct MAINLL *nextbar_p));
20 static void chktabcollision P((struct GRPSYL *start_p));
21 static void intertab P((struct GRPSYL *gs_p, struct MAINLL *mll_p));
22 static void setstems P((void));
23 static void setonestem P((struct GRPSYL *gs_p));
24 static void setopstem P((struct GRPSYL *gs1_p, struct GRPSYL *gs2_p));
25 static void setfreestem P((struct GRPSYL *gs1_p, struct GRPSYL *gs2_p));
26 static void set1freestem P((struct GRPSYL *this_p, struct GRPSYL *other_p,
28 static void setbeamedstem P((struct GRPSYL *start_p, int stemdir));
29 static void dobunch P((struct GRPSYL *start_p, struct GRPSYL *end_p));
30 static void dograce P((struct GRPSYL *gs1_p, struct GRPSYL *gs2_p));
31 static int setv3stem P((struct GRPSYL *gs_p, int stemdir));
32 static int dov3bunch P((struct GRPSYL *start_p, struct GRPSYL *end_p,
34 static void setheads P((void));
35 static void setvoiceheads P((struct MAINLL *mll_p, struct GRPSYL *gs_p,
36 int stafflines, short *shapes, int is_tab, int allx_hsi,
37 int sharps, int keylet));
38 static void fixoneline P((void));
43 * Abstract: Sets the relative vert coords of each note, and stem dir.
47 * Description: This function calls subroutines to set the relative vertical
48 * coordinates of each note and each note group (considering only
49 * the note heads in it at this point), stem directions, and which
50 * notehead characters to use.
57 debug(16, "setnotes");
68 * Abstract: Sets the relative vertical coordinates of each note.
72 * Description: This function loops through the main linked list, finding every
73 * STAFF structure. It calls a subroutine to process each list of
74 * list of GRPSYLs for groups (not syllables).
81 register struct MAINLL *mainll_p; /* point item in main linked list */
82 int v; /* index to voice linked lists */
83 int did_a_voice; /* have we processed a voice in meas?*/
84 struct TIMEDSSV *tssv_p; /* point along a timed SSV list */
85 struct MAINLL *nextbar_p; /* the next bar in the MLL */
88 debug(16, "locnotes");
89 initstructs(); /* clean out old SSV info */
91 did_a_voice = NO; /* prevent useless "used before set" warning */
92 nextbar_p = 0; /* prevent useless "used before set" warning */
95 * Loop through the main linked list, processing voices. MLL SSVs are
96 * assigned when encountered. But we also have to handle timed SSVs,
97 * because they may change the clef. This algorithm would be simpler
98 * if we called setssvstate() after each voice (to undo the timed
99 * SSVs), and then always reapplied them when we get to the next bar.
100 * But to save time, we don't undo them after the last voice, and so
101 * usually don't have to reassign them at the bar (unless all the
102 * visible voices had measure repeats, and so we never assigned any).
104 for (mainll_p = Mainllhc_p; mainll_p != 0; mainll_p = mainll_p->next) {
106 switch (mainll_p->str) {
108 asgnssv(mainll_p->u.ssv_p);
112 /* find the next bar line */
113 for (nextbar_p = mainll_p; nextbar_p->str != S_BAR;
114 nextbar_p = nextbar_p->next) {
117 /* we haven't processed a voice in this measure yet */
122 /* if invisible, there is nothing to do */
123 if (mainll_p->u.staff_p->visible == NO) {
127 /* loop through the voice(s), and process each list */
128 for (v = 0; v < MAXVOICES && mainll_p->u.staff_p
129 ->groups_p[v] != 0; v++) {
131 /* meas rpt/rest/space have no notes to do */
132 if (mainll_p->u.staff_p->groups_p[v]->is_meas
138 * If this is not the first voice we've done in
139 * this measure, and there are timed SSVs,
140 * locllnotes() assigned them when we were in
141 * there for the previous voice we did. So set
142 * the SSVs back to the state they were in at
143 * the start of the measure.
145 if (did_a_voice == YES && nextbar_p->u.bar_p->
147 setssvstate(mainll_p);
149 locllnotes(mainll_p, v, nextbar_p);
155 if (did_a_voice == NO) {
156 for (tssv_p = mainll_p->u.bar_p->timedssv_p;
158 tssv_p = tssv_p->next) {
159 asgnssv(&tssv_p->ssv);
170 * Abstract: Set the "stepsup" field for the notes in one GRPSYL list.
174 * Description: This function goes down one of the linked lists of GRPSYLs,
175 * one that is for groups, not syllables, and sets the stepsup
180 locllnotes(mll_p, v, nextbar_p)
182 struct MAINLL *mll_p; /* point at the MLL struct voice hangs off */
183 int v; /* voice to loop through */
184 struct MAINLL *nextbar_p; /* point at MLL for the next bar line */
187 register int upfromc4; /* steps up from middle C */
188 register int n; /* loop through all notes in a group */
189 int s; /* staff number */
190 int slines; /* lines in this staff */
191 int clef; /* the clef currently in operation */
192 int newclef; /* the new clef, in case it changes */
193 struct GRPSYL *gs_p; /* starts pointing at first GRPSYL in list */
194 struct TIMEDSSV *tssv_p;/* point along a timed SSV list */
195 RATIONAL offset; /* current group's offset into measure */
198 s = mll_p->u.staff_p->staffno;
199 debug(32, "locllnotes file=%s line=%d staff=%d vidx=%d",
200 mll_p->inputfile, mll_p->inputlineno, s, v);
201 slines = svpath(s, STAFFLINES)->stafflines;
203 /* find the initial clef for this staff */
204 clef = svpath(s, CLEF)->clef;
206 /* point at the first timed SSV for this measure, if there is one */
207 tssv_p = nextbar_p->u.bar_p->timedssv_p;
208 offset = Zero; /* first group's offset into measure */
210 /* loop through every group in this voice */
211 for (gs_p = mll_p->u.staff_p->groups_p[v]; gs_p != 0;
214 /* if no timed SSVs, don't waste time doing the following */
216 /* assign timed SSVs before current offset */
217 while (tssv_p != 0 && LT(tssv_p->time_off, offset)) {
218 asgnssv(&tssv_p->ssv);
219 tssv_p = tssv_p->next;
222 /* get clef state just before this group */
223 clef = svpath(s, CLEF)->clef;
225 /* assign timed SSVs at current offset */
226 while (tssv_p != 0 && EQ(tssv_p->time_off, offset)) {
227 asgnssv(&tssv_p->ssv);
228 tssv_p = tssv_p->next;
231 /* get clef for this group */
232 newclef = svpath(s, CLEF)->clef;
235 * If the clef changed at this time, set it in GRPSYL.
236 * This could happen with multiple voices on the staff.
237 * If so, we'll later erase clef from all but one; but
238 * the choice depends on the coords, which we don't
239 * know yet, so that is done later. The erasing is
240 * done in eraseclef() in restsyl.c.
242 if (newclef != clef) {
247 /* add our group's dur to get ready for next iteration*/
248 offset = radd(offset, gs_p->fulltime);
251 /* nothing more to do for rests or spaces */
252 if (gs_p->grpcont != GC_NOTES)
256 * We found a group consisting of notes, normal or tablature.
257 * First handle the tablature case.
259 if (clef == TABCLEF) {
261 * Make sure this voice's notes don't collide with
262 * some later voice's notes.
264 chktabcollision(gs_p);
266 for (n = 0; n < gs_p->nnotes; n++) {
268 * Set stepsup to be on the appropriate string.
270 /* calc steps up from middle of staff */
271 gs_p->notelist[n].stepsup = slines
272 - 1 - 2 * gs_p->notelist[n].STRINGNO;
280 * We found a non-tablature group consisting of notes. For
281 * each note, find the number of steps it is up from middle C
282 * and from the center line of the staff. (However, for 1-line
283 * staffs, we assume center line for now.)
284 * For CSS notes, we apply an offset to keep it far from the
285 * normal notes. This is so that setgrps.c will understand
286 * that CSS and non-CSS notes in a group never interfere.
287 * Later, absvert.c will find the true stepsup on the other
290 for (n = 0; n < gs_p->nnotes; n++) {
291 /* set steps up from middle line of staff */
293 /* get steps up from middle C */
294 upfromc4 = (gs_p->notelist[n].octave - 4) * 7 +
295 Letshift[ gs_p->notelist[n].letter - 'a' ];
297 gs_p->notelist[n].stepsup = upfromc4
299 if (gs_p->stemto == CS_ABOVE &&
300 n <= gs_p->stemto_idx) {
301 gs_p->notelist[n].stepsup += CSS_STEPS;
302 } else if (gs_p->stemto == CS_BELOW &&
303 n >= gs_p->stemto_idx) {
304 gs_p->notelist[n].stepsup -= CSS_STEPS;
307 /* 1-line staff; assume center line for now */
308 gs_p->notelist[n].stepsup = 0;
314 * Assign any timed SSVs that came after the last group, so that we are
315 * in the right state for the next measure (if we are the last voice).
317 while (tssv_p != 0) {
318 asgnssv(&tssv_p->ssv);
319 tssv_p = tssv_p->next;
324 * Name: chktabcollision()
326 * Abstract: Error if this GRPSYL conflicts with others on this staff.
330 * Description: This function checks for collisions between notes in this
331 * GRPSYL and notes in GRPSYLs of later voices in this chord on
332 * this staff. On a tab staff, no two voices are allowed to use
333 * the same string at the same time. If the frets are different,
334 * it would be impossible to play, and it seems best to disallow
335 * it even if they agreed. So if this happens, do an l_ufatal.
339 chktabcollision(start_p)
341 struct GRPSYL *start_p; /* first voice on this staff in this chord */
344 int sv[MAXTABLINES]; /* which voice, if any, is using each string */
345 int sidx; /* string index, starting at 0 */
346 struct GRPSYL *gs_p; /* a GRPSYL on this staff in this chord */
347 int n; /* loop through notes (frets) in GRPSYL */
350 /* if this chord has no more voices on this staff, return */
351 if (start_p->gs_p == 0 ||
352 start_p->gs_p->grpsyl == GS_SYLLABLE ||
353 start_p->gs_p->staffno != start_p->staffno)
356 /* we care only about notes (frets); rests and spaces are invisible */
357 if (start_p->grpcont != GC_NOTES)
360 /* init each string to an invalid voice number */
361 for (sidx = 0; sidx < MAXTABLINES; sidx++) {
366 * Loop from this voice through the last voice on this staff that has
367 * a GRPSYL in this chord. Don't worry about preceding voices; they
368 * already were in here and were checked against all these voices.
370 for (gs_p = start_p; gs_p != 0 && start_p->gs_p->grpsyl == GS_GROUP &&
371 gs_p->staffno == start_p->staffno; gs_p = gs_p->gs_p) {
373 /* put each note into array, checking if string already used */
374 for (n = 0; n < gs_p->nnotes; n++) {
376 if (sv[(int)gs_p->notelist[n].STRINGNO] != 0) {
378 l_ufatal(start_p->inputfile,
379 start_p->inputlineno,
380 "voices %d and %d on staff %d are using the \"%s\" string at the same time",
381 sv[(int)gs_p->notelist[n].STRINGNO],
384 stringname(gs_p->notelist[n].STRINGNO,
388 sv[(int)gs_p->notelist[n].STRINGNO] = gs_p->vno;
396 * Abstract: Do additional work between tablature groups.
400 * Description: This function does checks to prevent certain bend sequences
401 * on a tab staff. (It's unclear how such things would be drawn.)
402 * Also, when it finds the end of a single consecutive bend, it
403 * alters the previously set northern group boundaries of the
404 * groups, so that the arrows pointing at the bend strings will go
405 * up and down appropriately.
407 * This function is called only with groups that have real bends
408 * (regular or prebends).
410 #define MAXBDIST 20 /* no. of unique bend distances in a sequence*/
413 intertab(gs_p, mll_p)
415 struct GRPSYL *gs_p; /* point at current tablature group */
416 struct MAINLL *mll_p; /* point at the main LL struct it hangs off */
419 RATIONAL bdist[MAXBDIST]; /* array of bend distances */
420 RATIONAL bd; /* a bend distance */
421 int bdidx; /* index into table of bend distances*/
422 struct GRPSYL *nextgs_p; /* point at the next GRPSYL */
423 struct GRPSYL *gs2_p; /* point at earlier GRPSYLs */
424 struct MAINLL *mll2_p; /* needed for crossing bar lines */
425 int count, count2; /* count numbers of bends */
426 int n, k, j; /* loop variables */
427 int idx; /* index into a notelist */
428 int bad; /* was a bad thing found? */
431 /* count how many nonnull bends end at this group, remember last one */
433 idx = 0; /* prevent useless 'used before set' warning */
434 for (n = 0; n < gs_p->nnotes; n++) {
435 if (HASREALBEND(gs_p->notelist[n])) {
437 idx = n; /* remember where bend is */
441 /* enforce restrictions on the following group, if there is one */
442 mll2_p = mll_p; /* we don't want to disturb mll_p */
443 nextgs_p = nextgrpsyl(gs_p, &mll2_p);
444 count2 = 0; /* how many nonnull nonprebend bends are in *nextgs_p */
446 if (nextgs_p != 0 && nextgs_p->grpcont == GC_NOTES) {
448 bad = NO; /* init to "nothing is bad" */
450 for (n = 0; n < nextgs_p->nnotes; n++) {
452 /* if this note has a nonnull nonprebend bend */
453 if (HASREALBEND(nextgs_p->notelist[n]) &&
454 nextgs_p->notelist[n].FRETNO == NOFRET) {
458 l_ufatal(gs_p->inputfile,
460 "no bend (other than a release) is allowed to follow a multiple string bend");
464 l_ufatal(gs_p->inputfile,
466 "only single string bends are allowed to be consecutive");
469 if (nextgs_p->notelist[n].STRINGNO !=
470 gs_p->notelist[idx].STRINGNO) {
476 * We check "bad" here instead of inside the above loop,
477 * because we want to give priority to the "only single string
478 * bends . . ." message if that condition is happening.
481 l_ufatal(gs_p->inputfile, gs_p->inputlineno,
482 "consecutive bends must be on the same string");
487 * We know the current group has bend(s). If the following group has
488 * a nonnull nonprebend bend, just return now. We will handle this
489 * bend sequence when we find the last nonnull bend in it.
495 * Loop backwards through the sequence of bends. The start should be
496 * either a bend following no nonnull bend, or a prebend. While
497 * searching, build a table of all the unique bend distances. Usually
498 * we break out by finding a group with a nonnull bend, which means we
499 * went one too far with gs2_p, and gs_p is the start of the sequence.
500 * But if we hit the start, gs2_p will become 0 and we get out of the
501 * loop naturally. Again, gs_p is the start of the sequence.
503 bdidx = 0; /* number of unique bend distances found */
506 /* find which note, if any, has the bend in this group */
507 for (n = 0; n < gs2_p->nnotes; n++) {
508 if (HASREALBEND(gs2_p->notelist[n])) {
509 bd = ratbend(&gs2_p->notelist[n]);
514 if (n < gs2_p->nnotes) {
516 * We found a nonnull bend. Search the bdist array to
517 * see if this value has already occurred. Get out
518 * when the value is found, or when we find a greater
519 * value (the list is in ascending order).
521 for (k = 0; k < bdidx; k++) {
522 if (GE(bdist[k], bd))
526 /* bd > everything in the array */
527 /* add it at the end */
530 } else if (GT(bdist[k], bd)) {
531 /* bd should be put at this position */
532 /* move all later ones down a notch */
533 for (j = bdidx - 1; j >= k; j--)
534 bdist[j+1] = bdist[j];
538 /* else bd is already in the table */
540 if (bdidx >= MAXBDIST)
541 pfatal("too many unique bend distances in sequence of bends");
542 /* if this bend was a prebend, break */
543 if (gs2_p->notelist[n].FRETNO != NOFRET) {
544 gs_p = gs2_p; /* series starts at prebend */
548 /* there was no bend; start at the following group; */
549 /* gs_p is now the beginning of the sequence */
554 * It was a nonprebend bend. Point gs2_p to the preceding
555 * group, remember the one we just looked at in gs_p, and keep
559 gs2_p = prevgrpsyl(gs2_p, &mll_p);
563 * Loop forward through these groups. For each one, alter its northern
564 * boundary according to where its bend distance occurs in the bdist
565 * table. This will cause the print phase to print the bend strings
566 * at varying heights so that the arrows will bend up and down as
569 while (gs_p != nextgs_p && gs_p != 0) {
570 /* find which note has the bend in this group, get distance */
571 for (n = 0; n < gs_p->nnotes; n++) {
572 if (HASREALBEND(gs_p->notelist[n])) {
573 bd = ratbend(&gs_p->notelist[n]);
577 /* find distance in table, raise RN proportionally to index */
578 for (n = 0; n < bdidx; n++) {
579 if (EQ(bdist[n], bd)) {
580 gs_p->c[RN] += 3.0 * STEPSIZE * TABRATIO * n;
585 gs_p = nextgrpsyl(gs_p, &mll_p);
592 * Abstract: Sets stem direction for each group.
596 * Description: This function sets the stem direction for each group, based
597 * on the voice scheme at the time and other factors.
604 /* remember the previous stem direction of voice 3 on each staff */
605 short v3stemdir[MAXSTAFFS + 1];
607 int staffno; /* staff number */
608 int n; /* loop variable */
609 register struct MAINLL *mainll_p; /* point at main linked list item */
610 int vscheme; /* current voice scheme */
613 debug(16, "setstems");
614 initstructs(); /* clean out old SSV info */
616 /* set initial default direction of voice 3 stems to be UP */
617 for (n = 1; n <= MAXSTAFFS; n++)
621 * Loop once for each item in the main linked list. Apply any SSVs
622 * that are found. Call subroutines to process linked lists of
625 for (mainll_p = Mainllhc_p; mainll_p != 0; mainll_p = mainll_p->next) {
626 if (mainll_p->str == S_SSV) {
628 asgnssv(mainll_p->u.ssv_p);
630 } else if (mainll_p->str == S_STAFF &&
631 mainll_p->u.staff_p->visible == YES &&
632 ! is_mrpt(mainll_p->u.staff_p->groups_p[0])) {
634 * We've found a visible staff, which will have one
635 * or more voices, depending on the voice scheme.
637 staffno = mainll_p->u.staff_p->staffno;
638 vscheme = svpath(staffno, VSCHEME)->vscheme;
643 * There's only one voice on this staff, so
644 * call a routine to decide which way to point
645 * each stem. It handles both grace & nongrace.
647 setonestem(mainll_p->u.staff_p->groups_p[0]);
652 * There are two voices on this staff, and
653 * the stems are always supposed to point
654 * opposite. Call a routine to mark their
655 * stem directions. It handles both nongrace
658 setopstem(mainll_p->u.staff_p->groups_p[0],
659 mainll_p->u.staff_p->groups_p[1]);
664 * There are two voices on this staff, and
665 * the stems are free to point either way
666 * when one voice is a space. Call routines
667 * to mark their stem directions; first
668 * nongrace, then grace.
670 setfreestem(mainll_p->u.staff_p->groups_p[0],
671 mainll_p->u.staff_p->groups_p[1]);
672 dograce(mainll_p->u.staff_p->groups_p[0],
673 mainll_p->u.staff_p->groups_p[1]);
679 * This is just like V_2OPSTEM for the first
680 * two voices, but also allows a voice 3.
682 setopstem(mainll_p->u.staff_p->groups_p[0],
683 mainll_p->u.staff_p->groups_p[1]);
684 v3stemdir[staffno] = setv3stem(
685 mainll_p->u.staff_p->groups_p[2],
691 * This is just like V_2FREESTEM for the first
692 * two voices, but also allows a voice 3.
694 setfreestem(mainll_p->u.staff_p->groups_p[0],
695 mainll_p->u.staff_p->groups_p[1]);
696 dograce(mainll_p->u.staff_p->groups_p[0],
697 mainll_p->u.staff_p->groups_p[1]);
698 v3stemdir[staffno] = setv3stem(
699 mainll_p->u.staff_p->groups_p[2],
711 * Abstract: Sets stem direction for each group in a linked list for V_1.
715 * Description: This function sets the stem direction for each group in a
716 * linked list for a voice/measure, for the case where there is
717 * only one voice on the staff.
723 struct GRPSYL *gs_p; /* starts pointing at the first GRPSYL in a list */
726 register struct GRPSYL *start_p, *end_p; /* first and last of a set */
729 debug(32, "setonestem file=%s line=%d", gs_p->inputfile,
732 * Loop once for each bunch of groups that must be stemmed the same
733 * way. A beamed group must all be stemmed the same way, but nonbeamed
734 * notes are independent.
739 * Find next group that has nongrace notes. While doing this,
740 * set the stemdir for any grace groups encountered. For V_1,
741 * grace stems always go up.
743 while (start_p != 0 && (start_p->grpcont != GC_NOTES ||
744 start_p->grpvalue == GV_ZERO)) {
745 if (start_p->grpcont == GC_NOTES) /* must be grace */
746 start_p->stemdir = UP;
747 start_p = start_p->next;
749 if (start_p == 0) /* get out if no more this measure */
752 /* if this group is not beamed, handle it, and point at next */
753 if (start_p->beamloc == NOITEM) {
754 dobunch(start_p, start_p->next);
755 start_p = start_p->next;
760 * Find end of this beamed group, setting grace groups UP. If
761 * this is a cross staff beamed group, we may be starting at an
762 * INITEM or even the ENDITEM, since on this staff STARTITEM
763 * may have been a space. But that doesn't matter; we still
764 * look for ENDITEM, whether or not it's also a space; and
765 * dobunch handles these cases.
767 for (end_p = start_p; end_p != 0 &&
768 (end_p->grpvalue == GV_ZERO || end_p->beamloc != ENDITEM);
769 end_p = end_p->next) {
770 if (end_p->grpvalue == GV_ZERO)
774 pfatal("beamed group is not terminated");
776 /* handle this bunch of groups, and point at next */
777 dobunch(start_p, end_p->next);
778 start_p = end_p->next;
785 * Abstract: Sets stemdir for v1 or v2 groups for V_2OPSTEM/V_3OPSTEM.
789 * Description: This function sets the stem direction for each group in
790 * 2 linked lists for a staff/measure, for the case where
791 * the linked list is for voice 1 or voice 2 and stems are always
792 * supposed to be opposed. This function does both grace and
793 * nongrace groups. For this vscheme, they act the same.
794 * The user can force the stems against the normal direction,
795 * except that the parse phase blocks any forcing of grace groups.
799 setopstem(gs1_p, gs2_p)
801 register struct GRPSYL *gs1_p; /* starts at first GRPSYL in voice 1 list */
802 register struct GRPSYL *gs2_p; /* starts at first GRPSYL in voice 2 list */
805 debug(32, "setopstem file=%s line=%d", gs1_p->inputfile,
807 /* mark first voice's stems up */
809 /* if notes or starttime (needed for CSB), mark direction */
810 if (gs1_p->grpcont == GC_NOTES || gs1_p->beamloc == STARTITEM) {
811 /* if grace, or not in beamed group, try to set UP */
812 if (gs1_p->grpvalue == GV_ZERO ||
813 gs1_p->beamloc == NOITEM) {
814 /* if not forced by user, set UP */
815 if (gs1_p->stemdir == UNKNOWN) {
818 } else if (gs1_p->beamloc == STARTITEM) {
819 /* do same for all groups in beamed set */
820 setbeamedstem(gs1_p, UP);
826 /* mark second voice's stems down */
828 /* if notes or starttime (needed for CSB), mark direction */
829 if (gs2_p->grpcont == GC_NOTES || gs2_p->beamloc == STARTITEM) {
830 /* if grace, or not in beamed group, try to set DOWN */
831 if (gs2_p->grpvalue == GV_ZERO ||
832 gs2_p->beamloc == NOITEM) {
833 /* if not forced by user, set DOWN */
834 if (gs2_p->stemdir == UNKNOWN) {
835 gs2_p->stemdir = DOWN;
837 } else if (gs2_p->beamloc == STARTITEM) {
838 /* do same for all groups in beamed set */
839 setbeamedstem(gs2_p, DOWN);
847 * Name: setfreestem()
849 * Abstract: Sets stemdir for each group in 2 linked lists for V_2FREESTEM.
853 * Description: This function sets the stem direction for each (nongrace)
854 * group in 2 linked lists for a staff/measure, for the case
855 * where there are two voices on the staff and the stems are
856 * allowed to point either way for one voice when the other
861 setfreestem(gs1_p, gs2_p)
863 struct GRPSYL *gs1_p; /* starts pointing at first GRPSYL in voice 1 list */
864 struct GRPSYL *gs2_p; /* starts pointing at first GRPSYL in voice 2 list */
867 debug(32, "setfreestem file=%s line=%d", gs1_p->inputfile,
869 /* call to handle first voice, then call to handle second voice */
870 set1freestem(gs1_p, gs2_p, UP);
871 set1freestem(gs2_p, gs1_p, DOWN);
875 * Name: set1freestem()
877 * Abstract: Sets stemdir for v1 or v2 groups for V_2FREESTEM/V_3FREESTEM.
881 * Description: This function sets the stem direction for each (nongrace)
882 * group in one linked list for a staff/measure, for the case
883 * where the linked list is for voice 1 or voice 2 and stems are
884 * allowed to point either way for one voice when the other
885 * voice has a space. The function sets the directions just
886 * for "this" voice; the other voice is only used as a reference
887 * (we need to check when it has spaces).
891 set1freestem(this_p, other_p, stemdir)
893 struct GRPSYL *this_p; /* starts pointing at first GRPSYL in linked list */
894 /* for the voice whose stems we are now setting */
895 struct GRPSYL *other_p; /* starts pointing at first GRPSYL in linked list */
896 /* for the other voice */
897 int stemdir; /* which way the stem must point if forced */
900 register struct GRPSYL *start_p, *end_p; /* first and last of a set */
901 RATIONAL vtime, vtime2; /* elapsed time this measure */
904 debug(32, "set1freestem file=%s line=%d stemdir=%d", this_p->inputfile,
905 this_p->inputlineno, stemdir);
906 vtime = Zero; /* init to no time elapsed */
909 * Loop once for each bunch of groups in this voice that must be
910 * stemmed the same way. A beamed group must all be stemmed the same
911 * way, but nonbeamed notes are independent.
916 * Find next group that has nongrace notes, accumulating
917 * elapsed time. This code depends on grace notes having
920 while (start_p != 0 && (start_p->grpcont != GC_NOTES ||
921 start_p->grpvalue == GV_ZERO)) {
922 vtime = radd(vtime, start_p->fulltime);
923 start_p = start_p->next;
925 if (start_p == 0) /* get out if no more this measure */
928 /* if this group is not beamed, handle it, and point at next */
929 if (start_p->beamloc == NOITEM) {
930 vtime2 = radd(vtime, start_p->fulltime);
932 if (hasspace(other_p, vtime, vtime2)) {
933 /* other voice has space; decide stem */
934 dobunch(start_p, start_p->next);
937 * The other voice has notes/rests; force the
938 * the direction, unless the user has already
941 if (start_p->stemdir == UNKNOWN) {
942 start_p->stemdir = (short)stemdir;
946 start_p = start_p->next;
951 /* find end of this beamed group, ignoring grace groups */
953 for (end_p = start_p; end_p != 0 &&
954 (end_p->grpvalue == GV_ZERO || end_p->beamloc != ENDITEM);
956 vtime2 = radd(vtime2, end_p->fulltime);
958 pfatal("beamed group is not terminated");
959 vtime2 = radd(vtime2, end_p->fulltime); /* add in final note */
961 /* handle this bunch of groups, and point at next */
962 if (hasspace(other_p, vtime, vtime2)) {
963 /* other voice has space; decide our stems */
964 dobunch(start_p, end_p->next);
966 /* other voice has notes/rests; this forces ours */
967 setbeamedstem(start_p, stemdir);
971 start_p = end_p->next;
976 * Name: setbeamedstem()
978 * Abstract: Sets stem direction in beamed set, favoring one direction.
982 * Description: This function is given the first group in a nongrace beamed
983 * set. It sets all the stem directions, the same way of course.
984 * It sets them to the given stemdir, unless the user has
985 * overridden the direction.
989 setbeamedstem(start_p, stemdir)
991 struct GRPSYL *start_p; /* point at the first GRPSYL in beamed set */
992 int stemdir; /* which way we will try to point the stems */
995 struct GRPSYL *g_p; /* point into the set */
996 int forcedir; /* direction forced by user */
999 forcedir = UNKNOWN; /* no forcing yet */
1001 /* look for groups in this set where the user has forced stemdir */
1002 for (g_p = start_p; g_p != 0; g_p = g_p->next) {
1003 /* consider only nongrace note groups */
1004 if (g_p->grpcont != GC_NOTES || g_p->grpvalue == GV_ZERO) {
1007 /* if user forced the stemdir */
1008 if (g_p->stemdir != UNKNOWN) {
1009 if (forcedir == UNKNOWN) {
1010 /* first such occurrence; remember it */
1011 forcedir = g_p->stemdir;
1012 } else if (g_p->stemdir != forcedir) {
1013 /* any later occurrence must agree */
1014 l_warning(g_p->inputfile, g_p->inputlineno,
1015 "cannot have both 'up' and 'down' stem in same set of beamed or 'alt'-ed note groups");
1016 forcedir = g_p->stemdir; /* use latest */
1019 if (g_p->beamloc == ENDITEM) {
1024 /* if user forced any stems, we'll go with that direction */
1025 if (forcedir != UNKNOWN) {
1029 /* set all the stems in this set */
1030 for (g_p = start_p; g_p != 0; g_p = g_p->next) {
1031 if (g_p->grpcont != GC_NOTES || g_p->grpvalue == GV_ZERO) {
1034 g_p->stemdir = stemdir;
1035 if (g_p->beamloc == ENDITEM) {
1043 * Abstract: Sets stem direction for a single group or a beamed set.
1047 * Description: This function is given a single (nongrace) group, or a set
1048 * of them that will be beamed together, for the case where
1049 * the stems are allowed to go either way. It decides which
1050 * way is best, and sets the result.
1054 dobunch(start_p, end_p)
1056 struct GRPSYL *start_p; /* starts pointing at the first GRPSYL in a bunch */
1057 struct GRPSYL *end_p; /* starts pointing after the last GRPSYL in a bunch */
1060 register struct GRPSYL *gs_p; /* point along list of them */
1061 int lonesum; /* sum of offsets of single notes from center*/
1062 int topsum; /* sum of offsets of top notes from center */
1063 int botsum; /* sum of offsets of bottom notes from center*/
1064 int insum; /* sum of offsets of inner notes from center */
1065 int n; /* loop counter */
1066 int stemdir; /* answer of where stems should point */
1070 * Loop through all (nongrace) notes in these group(s), adding up
1071 * the offsets of their outer notes from the center line. For groups
1072 * that have only one note, count this in lonesum. For other groups,
1073 * count the top notes and bottom notes separately. We consider only
1074 * outer notes in these counters, and we count single note groups
1075 * separately to avoid counting the same note twice. But to be able to
1076 * breaks ties in the best way, we keep a separate counter for inner
1077 * notes of groups that have 3 or more notes.
1078 * While doing this, also keep track of whether the user requested a
1079 * specific stem direction on any of these groups. If so, there must
1080 * not be any contradictions between what they asked for.
1082 lonesum = topsum = botsum = insum = 0;
1083 stemdir = UNKNOWN; /* user hasn't asked for anything yet */
1084 for (gs_p = start_p; gs_p != end_p; gs_p = gs_p->next) {
1086 * Consider only note groups. Cross staff beaming can have
1087 * spaces in the list of groups, and rests need to be skipped.
1089 if (gs_p->grpcont == GC_NOTES && gs_p->grpvalue == GV_NORMAL) {
1090 if (gs_p->stemdir != UNKNOWN) {
1091 if (stemdir == UNKNOWN) {
1092 stemdir = gs_p->stemdir;
1093 } else if (gs_p->stemdir != stemdir) {
1094 l_warning(gs_p->inputfile,
1096 "cannot have both 'up' and 'down' stem in same set of beamed or 'alt'-ed note groups");
1097 stemdir = gs_p->stemdir;
1101 if (gs_p->nnotes == 1) {
1102 lonesum += gs_p->notelist[0].stepsup;
1104 topsum += gs_p->notelist[0].stepsup;
1105 botsum += gs_p->notelist[ gs_p->nnotes - 1 ].
1109 /* this loop happens only if >= 3 notes in the group */
1110 for (n = 1; n < gs_p->nnotes - 1; n++ ) {
1111 insum += gs_p->notelist[n].stepsup;
1117 * If the user requested a stem direction, that's what they will get,
1118 * for 5-line regular staffs, but for 1-line regular staffs stems are
1119 * always UP and for tablature staffs, always DOWN. For tab staffs, the
1120 * parse phase blocks any user requests for stemdir, so we don't have
1121 * to cover that in the warning and error messages here.
1123 * For a regular 5-line staff where the user didn't specify, if we are
1124 * involved in cross staff beaming, the direction defaults such that
1125 * the beam ends up between the two staffs; else, these rules apply:
1126 * If lonesum + topsum + botsum is positive, the "average" outer note
1127 * in these group(s) is above the center line, so the stems should go
1128 * down. If negative, they should go up. In case of tie, they should
1129 * go down, unless we can break the tie by using the inner notes.
1130 * For 1-line staff, the stem should go up, regardless.
1132 if (svpath(start_p->staffno, STAFFLINES)->stafflines == 5 &&
1133 is_tab_staff(start_p->staffno) == NO) {
1134 if (stemdir == UNKNOWN) {
1135 switch (start_p->beamto) {
1136 case CS_ABOVE: /* bm with staff above */
1139 case CS_BELOW: /* bm with staff below */
1142 case CS_SAME: /* no cross staff beaming */
1143 /* normal case: base on note distances */
1144 if (lonesum + topsum + botsum > 0)
1146 else if (lonesum + topsum + botsum < 0)
1149 stemdir = insum >= 0 ? DOWN : UP;
1153 } else if (is_tab_staff(start_p->staffno) == YES) {
1156 if (stemdir == DOWN)
1157 l_ufatal(start_p->inputfile, start_p->inputlineno,
1158 "cannot specify 'down' stem on voice 1 or 2 of a one-line staff");
1160 l_warning(start_p->inputfile, start_p->inputlineno,
1161 "stem direction should not be specified on voice 1 or 2 of a one-line staff");
1162 stemdir = UP; /* in case it was UNKNOWN */
1165 /* mark all groups (doesn't hurt to mark rests and spaces too) */
1166 for (gs_p = start_p; gs_p != end_p; gs_p = gs_p->next) {
1167 if (gs_p->grpvalue == GV_NORMAL)
1168 gs_p->stemdir = (short)stemdir;
1175 * Abstract: Sets stem direction for a single grace group.
1179 * Description: This function sets stem directions for grace groups when the
1180 * vscheme V_2FREESTEM. (The V_1 and V_2OPSTEM cases were handled
1181 * along with nongrace groups.) If the next nongrace group occurs
1182 * at a time when the other voice has a space, the grace stem goes
1183 * up (like V_1), else the same as the main group (like V_2OPSTEM).
1184 * For the first voice, these rules boil down to the fact that
1185 * graces stems are always up. The second voice can end up
1190 dograce(gs1_p, gs2_p)
1192 register struct GRPSYL *gs1_p; /* starts at first GRPSYL in voice 1 list */
1193 register struct GRPSYL *gs2_p; /* starts at first GRPSYL in voice 2 list */
1196 register struct GRPSYL *gs_p; /* point along list of them */
1197 RATIONAL vtime; /* elapsed time in measure */
1198 static RATIONAL tiny = {1, 4 * MAXBASICTIME};
1201 /* for the first voice, mark all grace stems up */
1202 for (gs_p = gs1_p; gs_p != 0; gs_p = gs_p->next) {
1203 if (gs_p->grpvalue == GV_ZERO)
1208 * For the 2nd voice, loop though all groups. For each nongrace group,
1209 * accumulate the fulltime. For each grace group, find out if the
1210 * other voice has a space at the moment the following nongrace group
1211 * starts. If so, treat as V_1. If not, treat as V_2OPSTEM.
1214 for (gs_p = gs2_p; gs_p != 0; gs_p = gs_p->next) {
1215 if (gs_p->grpvalue == GV_NORMAL) {
1216 vtime = radd(vtime, gs_p->fulltime);
1218 /* does other voice have space? */
1219 if (hasspace(gs1_p, vtime, radd(vtime, tiny)) == YES) {
1222 gs_p->stemdir = DOWN;
1231 * Abstract: Sets stem direction for each group in a linked list for voice 3.
1233 * Returns: default stem direction after this measure
1235 * Description: This function sets the stem direction for each group in a
1236 * linked list for a voice/measure that is for voice 3. Voice 3
1237 * ignores the other voices.
1241 setv3stem(gs_p, stemdir)
1243 struct GRPSYL *gs_p; /* starts pointing at the first GRPSYL in a list */
1244 int stemdir; /* stem direction of the previous group */
1247 register struct GRPSYL *start_p, *end_p; /* first and last of a set */
1250 debug(32, "setv3stem file=%s line=%d", gs_p->inputfile,
1253 * Loop once for each bunch of groups that must be stemmed the same
1254 * way. A beamed group must all be stemmed the same way, but nonbeamed
1255 * notes are independent.
1260 * Find next group that has nongrace notes. While doing this,
1261 * set the stemdir for any grace groups encountered. For voice
1262 * 3, grace stems always go up.
1264 while (start_p != 0 && (start_p->grpcont != GC_NOTES ||
1265 start_p->grpvalue == GV_ZERO)) {
1266 if (start_p->grpcont == GC_NOTES) /* must be grace */
1267 start_p->stemdir = UP;
1268 start_p = start_p->next;
1270 if (start_p == 0) /* get out if no more this measure */
1273 /* if this group is not beamed, handle it, and point at next */
1274 if (start_p->beamloc == NOITEM) {
1275 stemdir = dov3bunch(start_p, start_p->next, stemdir);
1276 start_p = start_p->next;
1281 * Find end of this beamed group, setting grace groups UP.
1282 * Note that voice 3 does not allow cross staff beaming.
1284 for (end_p = start_p; end_p != 0 &&
1285 (end_p->grpvalue == GV_ZERO || end_p->beamloc != ENDITEM);
1286 end_p = end_p->next) {
1287 if (end_p->grpvalue == GV_ZERO)
1288 end_p->stemdir = UP;
1291 pfatal("beamed group is not terminated");
1293 /* handle this bunch of groups, and point at next */
1294 stemdir = dov3bunch(start_p, end_p->next, stemdir);
1295 start_p = end_p->next;
1304 * Abstract: Sets stem dir for a single group or a beamed set on voice 3.
1306 * Returns: stem direction that was chosen
1308 * Description: This function is given a single (nongrace) group, or a set
1309 * of them that will be beamed together, for voice 3. It decides
1310 * which stemdir is needed, and sets it for each group.
1314 dov3bunch(start_p, end_p, stemdir)
1316 struct GRPSYL *start_p; /* starts pointing at the first GRPSYL in a bunch */
1317 struct GRPSYL *end_p; /* starts pointing after the last GRPSYL in a bunch */
1318 int stemdir; /* stem direction of the previous group */
1321 register struct GRPSYL *gs_p; /* point along list of them */
1322 int userdir; /* stemdir requested by user */
1326 * Loop through all groups in this bunch, keeping track of any user-
1327 * specified direction. Grace groups are forced to UP but are other-
1328 * wise ignored. Nongrace groups could be rests, so ignore them.
1330 userdir = UNKNOWN; /* user hasn't asked for anything yet */
1331 for (gs_p = start_p; gs_p != end_p; gs_p = gs_p->next) {
1332 if (gs_p->grpvalue == GV_ZERO) {
1333 gs_p->stemdir = UP; /* grace group */
1334 } else if (gs_p->grpcont == GC_NOTES) {
1335 if (gs_p->stemdir != UNKNOWN) { /* user request */
1336 if (userdir == UNKNOWN) {
1337 userdir = gs_p->stemdir;
1338 } else if (gs_p->stemdir != userdir) {
1339 l_warning(gs_p->inputfile,
1341 "cannot have both 'up' and 'down' stem in same set of beamed or 'alt'-ed note groups");
1342 userdir = gs_p->stemdir;
1348 /* if user requested a direction, we will use that, else keep previous*/
1349 if (userdir != UNKNOWN)
1352 /* mark all nongrace groups; it doesn't hurt to mark rests */
1353 for (gs_p = start_p; gs_p != end_p; gs_p = gs_p->next) {
1354 if (gs_p->grpvalue == GV_NORMAL)
1355 gs_p->stemdir = (short)stemdir;
1364 * Abstract: Set headshape, headfont, headchar, and coords for all notes.
1368 * Description: This function sets the headshape, headfont, and headchar for
1369 * all notes. (However, the headchar is changed later, in
1370 * setgrps.c, in certain cases where two GRPSYLs share a note.)
1371 * It also sets the relative vertical coords of the notes and
1372 * their groups. We waited until now to do this so that stemdir
1380 struct MAINLL *mainll_p; /* point at main linked list item */
1381 struct STAFF *staff_p; /* point at a STAFF */
1382 int stafflines; /* lines in a tablature staff */
1383 int is_tab; /* is this a tablature staff? */
1384 int sharps; /* in the key sig */
1385 char keylet; /* letter of the key, assuming major */
1386 short *shapes; /* 7 shapes for the 7 notes */
1387 int vidx; /* voice index */
1388 int allx_hsi; /* headshape index for allx */
1391 debug(16, "setheads");
1392 initstructs(); /* clean out old SSV info */
1394 /* just in case we'll need it later */
1395 allx_hsi = get_shape_num("allx");
1398 * Loop once for each item in the main linked list. Apply any SSVs
1399 * that are found. For each voice on each staff, call setvoiceheads
1400 * to do the the work.
1402 for (mainll_p = Mainllhc_p; mainll_p != 0; mainll_p = mainll_p->next) {
1404 if (mainll_p->str == S_SSV) {
1405 /* apply the SSV and go to the next item */
1406 asgnssv(mainll_p->u.ssv_p);
1410 /* deal only with visible staffs that aren't measure rpts */
1411 if (mainll_p->str != S_STAFF ||
1412 mainll_p->u.staff_p->visible == NO ||
1413 is_mrpt(mainll_p->u.staff_p->groups_p[0])) {
1418 * We found a staff to work on. Set up some variables we'll
1421 staff_p = mainll_p->u.staff_p;
1422 stafflines = svpath(staff_p->staffno, STAFFLINES)->stafflines;
1423 is_tab = svpath(staff_p->staffno, CLEF)->clef == TABCLEF;
1426 * Find the key letter. We don't care about any sharp or flat
1427 * in the key name, just the letter. For tab it's meaningless,
1430 sharps = eff_key(staff_p->staffno);
1431 keylet = Circle[(sharps + 1 + 7) % 7];
1433 /* loop through every possible voice on this staff */
1434 for (vidx = 0; vidx < MAXVOICES; vidx++) {
1436 /* point at array of headshapes for this voice */
1437 shapes = vvpath(staff_p->staffno, vidx + 1,
1438 NOTEHEADS)->noteheads;
1440 setvoiceheads(mainll_p, staff_p->groups_p[vidx],
1441 stafflines, shapes, is_tab, allx_hsi, sharps,
1448 * Name: setvoiceheads()
1450 * Abstract: Set headshape, headfont, headchar, and coords for one GRPSYL.
1454 * Description: This function sets the headshape, headfont, and headchar for
1455 * one GRPSYL. (However, the headchar is changed later, in
1456 * setgrps.c, in certain cases where two GRPSYLs share a note.)
1457 * It also sets the relative vertical coords of the notes and
1462 setvoiceheads(mll_p, gs_p, stafflines, shapes, is_tab, allx_hsi, sharps, keylet)
1464 struct MAINLL *mll_p; /* point at the main LL struct gs_p hangs off */
1465 struct GRPSYL *gs_p; /* starts at start of GRPSYL list */
1466 int stafflines; /* lines in a tablature staff */
1467 short *shapes; /* 7 shapes for the 7 notes */
1468 int is_tab; /* is this a tablature staff? */
1469 int allx_hsi; /* headshape index for allx */
1470 int sharps; /* in the key sig */
1471 int keylet; /* letter of the key, assuming major */
1474 float bendheight; /* total height of bend numbers */
1475 int havebend; /* any bends in this group? */
1476 int n; /* loop variable */
1477 int i; /* temp variable */
1478 int hfont; /* font of note head */
1479 int hchar; /* char of note head */
1480 float vhalf; /* half the vert size of note head */
1481 int stepsup; /* local copy */
1484 /* loop through every GRPSYL in voice (may be none) */
1485 for ( ; gs_p != 0; gs_p = gs_p->next) {
1487 /* we only care about notes, not rest/space */
1488 if (gs_p->grpcont != GC_NOTES) {
1492 bendheight = 0; /* init to no bends */
1496 * Loop through every note in the GRPSYL, setting its
1497 * headshape, head font/char, and coords.
1499 for (n = 0; n < gs_p->nnotes; n++) {
1501 /* if there is no note-level override... */
1502 if (gs_p->notelist[n].headshape == HS_UNKNOWN) {
1504 /* set to group-level override if present */
1505 gs_p->notelist[n].headshape = gs_p->headshape;
1508 * If still no setting (which is the usual
1509 * case), set according to what the SSVs said.
1510 * Set i to how far note is above the tonic
1511 * (assuming a major key). Tab uses tonic.
1512 * Then get shape from array.
1514 if (gs_p->notelist[n].headshape == HS_UNKNOWN) {
1517 i = 0; /* arbitrary */
1519 i = (gs_p-> notelist[n].letter
1523 gs_p->notelist[n].headshape = shapes[i];
1528 * Now that we know the stepsup (set in locllnotes())
1529 * and the headshape, we can set the note's coords.
1531 if (is_tab && gs_p->notelist[n].headshape != allx_hsi) {
1533 /* handle tab (except when it's an X) */
1535 gs_p->notelist[n].c[RY] = gs_p->notelist[n].
1536 stepsup * TABRATIO * STEPSIZE;
1538 if (gs_p->notelist[n].FRETNO == NOFRET) {
1539 /* set RN and RS the same as RY */
1540 gs_p->notelist[n].c[RN] =
1541 gs_p->notelist[n].c[RY];
1542 gs_p->notelist[n].c[RS] =
1543 gs_p->notelist[n].c[RY];
1546 * Set vertical coordinates of the
1547 * "note" (fret number). It is to be
1548 * centered on the appropriate line.
1550 vhalf = strheight(fret_string(&gs_p->
1551 notelist[n], gs_p)) / 2.0;
1552 gs_p->notelist[n].c[RN] =
1553 gs_p->notelist[n].c[RY] + vhalf;
1554 gs_p->notelist[n].c[RS] =
1555 gs_p->notelist[n].c[RY] - vhalf;
1560 /* handle non-tab and tab X-notes */
1562 /* find & store music font and char */
1563 hchar = nheadchar(gs_p->notelist[n].headshape,
1564 gs_p->basictime, gs_p->stemdir, &hfont);
1565 gs_p->notelist[n].headchar = hchar;
1566 gs_p->notelist[n].headfont = hfont;
1568 /* half the height of the note head */
1569 vhalf = height(hfont, gs_p->notelist[n].notesize
1570 == GS_NORMAL ? DFLT_SIZE : SMALLSIZE,
1574 * Set actual relative vertical coords. We need
1575 * to recalculate the original stepsup, which
1576 * was modified for CSS notes, because absvert.c
1577 * needs to know what the note's coords would
1578 * have been if it hadn't been CSS. Sigh.
1580 stepsup = gs_p->notelist[n].stepsup;
1581 switch (gs_p->stemto) {
1583 if (n <= gs_p->stemto_idx) {
1584 stepsup -= CSS_STEPS;
1588 if (n >= gs_p->stemto_idx) {
1589 stepsup += CSS_STEPS;
1593 gs_p->notelist[n].c[RY] = stepsup * STEPSIZE *
1594 (is_tab ? TABRATIO : 1.0);
1596 gs_p->notelist[n].c[RN] =
1597 gs_p->notelist[n].c[RY] + vhalf;
1599 gs_p->notelist[n].c[RS] =
1600 gs_p->notelist[n].c[RY] - vhalf;
1605 * If there was a real bend, add to total height
1606 * of the bend numbers.
1608 if (HASREALBEND(gs_p->notelist[n])) {
1609 bendheight += strheight(bend_string(
1610 &gs_p->notelist[n])) + STDPAD;
1613 /* if any bend at all, remember it */
1614 if (HASBEND(gs_p->notelist[n])) {
1621 * Set the group's coords.
1625 * Set the group's north based on the top of the top
1626 * bend number if there is one, otherwise the top of
1627 * the top fret number. We leave 3 "tab stepsizes" of
1628 * white space between the staff and the lowest bend
1629 * number, for the arrow.
1631 if (havebend == NO) { /* no bends present */
1632 /* there must be frets, since no bends */
1633 gs_p->c[RN] = gs_p->notelist[0].c[RN] + STDPAD;
1634 } else { /* bend(s) present */
1635 gs_p->c[RN] = (stafflines + 2) *
1636 STEPSIZE * TABRATIO + bendheight;
1640 * Set the group's south based on the bottom of the
1641 * bottom fret number if there is one, otherwise the
1642 * middle of the staff.
1644 if (gs_p->nnotes == 0) { /* no frets present */
1646 } else { /* frets present */
1647 gs_p->c[RS] = gs_p->notelist
1648 [ gs_p->nnotes - 1 ].c[RS] - STDPAD;
1651 /* if bends, do work between this and other groups */
1652 if (bendheight > 0) {
1653 intertab(gs_p, mll_p);
1657 * Non-tab: use the outermost non-CSS notes, but pad.
1658 * If all notes are CSS, then set RN and RS to zero.
1660 switch (gs_p->stemto) {
1662 gs_p->c[RN] = gs_p->notelist
1664 gs_p->c[RS] = gs_p->notelist
1665 [gs_p->nnotes-1].c[RS] - STDPAD;
1668 if (gs_p->stemto_idx == gs_p->nnotes - 1) {
1669 gs_p->c[RN] = gs_p->c[RS] = 0.0;
1671 gs_p->c[RN] = gs_p->notelist
1672 [gs_p->stemto_idx+1].c[RN] + STDPAD;
1673 gs_p->c[RS] = gs_p->notelist
1674 [gs_p->nnotes-1].c[RS] - STDPAD;
1678 if (gs_p->stemto_idx == 0) {
1679 gs_p->c[RN] = gs_p->c[RS] = 0.0;
1681 gs_p->c[RN] = gs_p->notelist
1683 gs_p->c[RS] = gs_p->notelist
1684 [gs_p->stemto_idx-1].c[RS] - STDPAD;
1693 * Name: fixoneline()
1695 * Abstract: Fix stemsup and vertical coord for notes on one-line staffs.
1699 * Description: stepsup and notes' vertical coords are set in locllnotes().
1700 * For one-line staffs, it assumes the notes are on the line.
1701 * But if the notes are not to be on the line, that isn't right.
1702 * It depends on which voice this is. Now that we have set the
1703 * stem direction, we need to correct this info.
1710 struct MAINLL *mainll_p; /* point at main linked list item */
1711 struct STAFF *staff_p; /* point at a STAFF */
1712 struct GRPSYL *gs_p; /* point along a GRPSYL list */
1713 int v; /* voice number, 0 or 1 */
1716 debug(16, "fixoneline");
1717 initstructs(); /* clean out old SSV info */
1720 * Loop once for each item in the main linked list. Apply any SSVs
1721 * that are found. Move notes that are not to be on the line.
1723 for (mainll_p = Mainllhc_p; mainll_p != 0; mainll_p = mainll_p->next) {
1725 if (mainll_p->str == S_SSV) {
1726 /* apply the SSV and go to the next item */
1727 asgnssv(mainll_p->u.ssv_p);
1731 /* deal only with visible staffs that aren't measure rpts */
1732 if (mainll_p->str != S_STAFF ||
1733 mainll_p->u.staff_p->visible == NO ||
1734 is_mrpt(mainll_p->u.staff_p->groups_p[0])) {
1738 staff_p = mainll_p->u.staff_p;
1740 /* deal only with non-tab one-line staffs */
1741 if (svpath(staff_p->staffno, STAFFLINES)->stafflines != 1 ||
1742 svpath(staff_p->staffno, CLEF)->clef
1748 * Loop through voices 1 and 2, and process each list. Note
1749 * that voice 3 is always on the line, so we don't need to do
1752 for (v = 0; v < NORMVOICES && staff_p->groups_p[v] != 0; v++) {
1754 /* change stepsup from 0 only if notes not on the line*/
1755 if (vvpath(staff_p->staffno, v + 1, ONTHELINE)->
1760 for (gs_p = staff_p->groups_p[v]; gs_p != 0;
1761 gs_p = gs_p->next) {
1763 /* only notes are to be changed */
1764 if (gs_p->grpcont != GC_NOTES) {
1768 /* move up or down a step based on voice */
1769 if (gs_p->vno == 1) {
1770 gs_p->notelist[0].stepsup = 1;
1771 gs_p->notelist[0].c[RY] = STEPSIZE;
1772 gs_p->notelist[0].c[RN] += STEPSIZE;
1773 gs_p->notelist[0].c[RS] += STEPSIZE;
1775 gs_p->notelist[0].stepsup = -1;
1776 gs_p->notelist[0].c[RY] = -STEPSIZE;
1777 gs_p->notelist[0].c[RN] -= STEPSIZE;
1778 gs_p->notelist[0].c[RS] -= STEPSIZE;