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
;