chiark / gitweb /
Import upstream version 5.3.
[mup] / mup / mup / setnotes.c
1 /* Copyright (c) 1995, 1996, 1997, 1998, 2000, 2001, 2003, 2004, 2005, 2006
2  * by Arkkra Enterprises */
3 /* All rights reserved */
4 /*
5  * Name:        setnotes.c
6  *
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.
11  */
12
13 #include "defines.h"
14 #include "structs.h"
15 #include "globals.h"
16
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,
27                 int stemdir));
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,
33                 int stemdir));
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));
39 \f
40 /*
41  * Name:        setnotes()
42  *
43  * Abstract:    Sets the relative vert coords of each note, and stem dir.
44  *
45  * Returns:     void
46  *
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.
51  */
52
53 void
54 setnotes()
55
56 {
57         debug(16, "setnotes");
58
59         locnotes();
60         setstems();
61         setheads();
62         fixoneline();
63 }
64 \f
65 /*
66  * Name:        locnotes()
67  *
68  * Abstract:    Sets the relative vertical coordinates of each note.
69  *
70  * Returns:     void
71  *
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).
75  */
76
77 static void
78 locnotes()
79
80 {
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 */
86
87
88         debug(16, "locnotes");
89         initstructs();                  /* clean out old SSV info */
90
91         did_a_voice = NO;       /* prevent useless "used before set" warning */
92         nextbar_p = 0;          /* prevent useless "used before set" warning */
93
94         /*
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).
103          */
104         for (mainll_p = Mainllhc_p; mainll_p != 0; mainll_p = mainll_p->next) {
105
106                 switch (mainll_p->str) {
107                 case S_SSV:
108                         asgnssv(mainll_p->u.ssv_p);
109                         break;
110
111                 case S_CHHEAD:
112                         /* find the next bar line */
113                         for (nextbar_p = mainll_p; nextbar_p->str != S_BAR;
114                                         nextbar_p = nextbar_p->next) {
115                                 ;
116                         }
117                         /* we haven't processed a voice in this measure yet */
118                         did_a_voice = NO;
119                         break;
120
121                 case S_STAFF:
122                         /* if invisible, there is nothing to do */
123                         if (mainll_p->u.staff_p->visible == NO) {
124                                 break;
125                         }
126
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++) {
130
131                                 /* meas rpt/rest/space have no notes to do */
132                                 if (mainll_p->u.staff_p->groups_p[v]->is_meas
133                                                 == YES) {
134                                         continue;
135                                 }
136
137                                 /*
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.
144                                  */
145                                 if (did_a_voice == YES && nextbar_p->u.bar_p->
146                                                         timedssv_p != 0){
147                                         setssvstate(mainll_p);
148                                 }
149                                 locllnotes(mainll_p, v, nextbar_p);
150                                 did_a_voice = YES;
151                         }
152                         break;
153
154                 case S_BAR:
155                         if (did_a_voice == NO) {
156                                 for (tssv_p = mainll_p->u.bar_p->timedssv_p;
157                                                 tssv_p != 0;
158                                                 tssv_p = tssv_p->next) {
159                                         asgnssv(&tssv_p->ssv);
160                                 }
161                         }
162                         break;
163                 }
164         }
165 }
166 \f
167 /*
168  * Name:        locllnotes()
169  *
170  * Abstract:    Set the "stepsup" field for the notes in one GRPSYL list.
171  *
172  * Returns:     void
173  *
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
176  *              value.
177  */
178
179 static void
180 locllnotes(mll_p, v, nextbar_p)
181
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 */
185
186 {
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 */
196
197
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;
202
203         /* find the initial clef for this staff */
204         clef = svpath(s, CLEF)->clef;
205
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 */
209
210         /* loop through every group in this voice */
211         for (gs_p = mll_p->u.staff_p->groups_p[v]; gs_p != 0;
212                                 gs_p = gs_p->next) {
213
214                 /* if no timed SSVs, don't waste time doing the following */
215                 if (tssv_p != 0) {
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;
220                         }
221
222                         /* get clef state just before this group */
223                         clef = svpath(s, CLEF)->clef;
224
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;
229                         }
230
231                         /* get clef for this group */
232                         newclef = svpath(s, CLEF)->clef;
233
234                         /*
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.
241                          */
242                         if (newclef != clef) {
243                                 clef = newclef;
244                                 gs_p->clef = clef;
245                         }
246
247                         /* add our group's dur to get ready for next iteration*/
248                         offset = radd(offset, gs_p->fulltime);
249                 }
250
251                 /* nothing more to do for rests or spaces */
252                 if (gs_p->grpcont != GC_NOTES)
253                         continue;
254
255                 /*
256                  * We found a group consisting of notes, normal or tablature.
257                  * First handle the tablature case.
258                  */
259                 if (clef == TABCLEF) {
260                         /*
261                          * Make sure this voice's notes don't collide with
262                          * some later voice's notes.
263                          */
264                         chktabcollision(gs_p);
265
266                         for (n = 0; n < gs_p->nnotes; n++) {
267                                 /*
268                                  * Set stepsup to be on the appropriate string.
269                                  */
270                                 /* calc steps up from middle of staff */
271                                 gs_p->notelist[n].stepsup = slines
272                                         - 1 - 2 * gs_p->notelist[n].STRINGNO;
273
274                         }
275
276                         continue;
277                 }
278
279                 /*
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
288                  * staff.
289                  */
290                 for (n = 0; n < gs_p->nnotes; n++) {
291                         /* set steps up from middle line of staff */
292                         if (slines == 5) {
293                                 /* get steps up from middle C */
294                                 upfromc4 = (gs_p->notelist[n].octave - 4) * 7 +
295                                 Letshift[ gs_p->notelist[n].letter - 'a' ];
296
297                                 gs_p->notelist[n].stepsup = upfromc4
298                                                 + clef - ALTO;
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;
305                                 }
306                         } else {
307                                 /* 1-line staff; assume center line for now */
308                                 gs_p->notelist[n].stepsup = 0;
309                         }
310                 }
311         }
312
313         /*
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).
316          */
317         while (tssv_p != 0) {
318                 asgnssv(&tssv_p->ssv);
319                 tssv_p = tssv_p->next;
320         }
321 }
322 \f
323 /*
324  * Name:        chktabcollision()
325  *
326  * Abstract:    Error if this GRPSYL conflicts with others on this staff.
327  *
328  * Returns:     void
329  *
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.
336  */
337
338 static void
339 chktabcollision(start_p)
340
341 struct GRPSYL *start_p;         /* first voice on this staff in this chord */
342
343 {
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 */
348
349
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)
354                 return;
355
356         /* we care only about notes (frets); rests and spaces are invisible */
357         if (start_p->grpcont != GC_NOTES)
358                 return;
359
360         /* init each string to an invalid voice number */
361         for (sidx = 0; sidx < MAXTABLINES; sidx++) {
362                 sv[sidx] = 0;
363         }
364
365         /*
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.
369          */
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) {
372
373                 /* put each note into array, checking if string already used */
374                 for (n = 0; n < gs_p->nnotes; n++) {
375
376                         if (sv[(int)gs_p->notelist[n].STRINGNO] != 0) {
377
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],
382                                          gs_p->vno,
383                                          gs_p->staffno,
384                                          stringname(gs_p->notelist[n].STRINGNO,
385                                                 gs_p->staffno));
386                         }
387
388                         sv[(int)gs_p->notelist[n].STRINGNO] = gs_p->vno;
389                 }
390         }
391 }
392 \f
393 /*
394  * Name:        intertab()
395  *
396  * Abstract:    Do additional work between tablature groups.
397  *
398  * Returns:     void
399  *
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.
406  *
407  *              This function is called only with groups that have real bends
408  *              (regular or prebends).
409  */
410 #define MAXBDIST        20      /* no. of unique bend distances in a sequence*/
411
412 static void
413 intertab(gs_p, mll_p)
414
415 struct GRPSYL *gs_p;            /* point at current tablature group */
416 struct MAINLL *mll_p;           /* point at the main LL struct it hangs off */
417
418 {
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? */
429
430
431         /* count how many nonnull bends end at this group, remember last one */
432         count = 0;
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])) {
436                         count++;
437                         idx = n;                /* remember where bend is */
438                 }
439         }
440
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 */
445
446         if (nextgs_p != 0 && nextgs_p->grpcont == GC_NOTES) {
447
448                 bad = NO;       /* init to "nothing is bad" */
449
450                 for (n = 0; n < nextgs_p->nnotes; n++) {
451
452                         /* if this note has a nonnull nonprebend bend */
453                         if (HASREALBEND(nextgs_p->notelist[n]) &&
454                             nextgs_p->notelist[n].FRETNO == NOFRET) {
455
456                                 count2++;
457                                 if (count > 1) {
458                                         l_ufatal(gs_p->inputfile,
459                                                 gs_p->inputlineno,
460                                                 "no bend (other than a release) is allowed to follow a multiple string bend");
461                                 }
462
463                                 if (count2 > 1) {
464                                         l_ufatal(gs_p->inputfile,
465                                                 gs_p->inputlineno,
466                                                 "only single string bends are allowed to be consecutive");
467                                 }
468
469                                 if (nextgs_p->notelist[n].STRINGNO !=
470                                                 gs_p->notelist[idx].STRINGNO) {
471                                         bad = YES;
472                                 }
473                         }
474                 }
475                 /*
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.
479                  */
480                 if (bad == YES) {
481                         l_ufatal(gs_p->inputfile, gs_p->inputlineno,
482                                 "consecutive bends must be on the same string");
483                 }
484         }
485
486         /*
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.
490          */
491         if (count2 > 0)
492                 return;
493
494         /*
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.
502          */
503         bdidx = 0;      /* number of unique bend distances found */
504         gs2_p = gs_p;
505         while (gs2_p != 0) {
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]);
510                                 break;
511                         }
512                 }
513
514                 if (n < gs2_p->nnotes) {
515                         /*
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).
520                          */
521                         for (k = 0; k < bdidx; k++) {
522                                 if (GE(bdist[k], bd))
523                                         break;
524                         }
525                         if (k == bdidx) {
526                                 /* bd > everything in the array */
527                                 /* add it at the end */
528                                 bdist[k] = bd;
529                                 bdidx++;
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];
535                                 bdist[k] = bd;
536                                 bdidx++;
537                         }
538                         /* else bd is already in the table */
539
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 */
545                                 break;
546                         }
547                 } else {
548                         /* there was no bend; start at the following group; */
549                         /* gs_p is now the beginning of the sequence */
550                         break;
551                 }
552
553                 /*
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
556                  * looping.
557                  */
558                 gs_p = gs2_p;
559                 gs2_p = prevgrpsyl(gs2_p, &mll_p);
560         }
561
562         /*
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
567          * appropriate.
568          */
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]);
574                                 break;
575                         }
576                 }
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;
581                                 break;
582                         }
583                 }
584
585                 gs_p = nextgrpsyl(gs_p, &mll_p);
586         }
587 }
588 \f
589 /*
590  * Name:        setstems()
591  *
592  * Abstract:    Sets stem direction for each group.
593  *
594  * Returns:     void
595  *
596  * Description: This function sets the stem direction for each group, based
597  *              on the voice scheme at the time and other factors.
598  */
599
600 static void
601 setstems()
602
603 {
604         /* remember the previous stem direction of voice 3 on each staff */
605         short v3stemdir[MAXSTAFFS + 1];
606
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 */
611
612
613         debug(16, "setstems");
614         initstructs();                  /* clean out old SSV info */
615
616         /* set initial default direction of voice 3 stems to be UP */
617         for (n = 1; n <= MAXSTAFFS; n++)
618                 v3stemdir[n] = UP;
619
620         /*
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
623          * groups.
624          */
625         for (mainll_p = Mainllhc_p; mainll_p != 0; mainll_p = mainll_p->next) {
626                 if (mainll_p->str == S_SSV) {
627
628                         asgnssv(mainll_p->u.ssv_p);
629
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])) {
633                         /*
634                          * We've found a visible staff, which will have one
635                          * or more voices, depending on the voice scheme.
636                          */
637                         staffno = mainll_p->u.staff_p->staffno;
638                         vscheme = svpath(staffno, VSCHEME)->vscheme;
639
640                         switch (vscheme) {
641                         case V_1:
642                                 /*
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.
646                                  */
647                                 setonestem(mainll_p->u.staff_p->groups_p[0]);
648                                 break;
649
650                         case V_2OPSTEM:
651                                 /*
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
656                                  * and grace.
657                                  */
658                                 setopstem(mainll_p->u.staff_p->groups_p[0],
659                                           mainll_p->u.staff_p->groups_p[1]);
660                                 break;
661
662                         case V_2FREESTEM:
663                                 /*
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.
669                                  */
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]);
674
675                                 break;
676
677                         case V_3OPSTEM:
678                                 /*
679                                  * This is just like V_2OPSTEM for the first
680                                  * two voices, but also allows a voice 3.
681                                  */
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],
686                                         v3stemdir[staffno]);
687                                 break;
688
689                         case V_3FREESTEM:
690                                 /*
691                                  * This is just like V_2FREESTEM for the first
692                                  * two voices, but also allows a voice 3.
693                                  */
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],
700                                         v3stemdir[staffno]);
701
702                                 break;
703                         }
704                 }
705         }
706 }
707 \f
708 /*
709  * Name:        setonestem()
710  *
711  * Abstract:    Sets stem direction for each group in a linked list for V_1.
712  *
713  * Returns:     void
714  *
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.
718  */
719
720 static void
721 setonestem(gs_p)
722
723 struct GRPSYL *gs_p;    /* starts pointing at the first GRPSYL in a list */
724
725 {
726         register struct GRPSYL *start_p, *end_p; /* first and last of a set */
727
728
729         debug(32, "setonestem file=%s line=%d", gs_p->inputfile,
730                         gs_p->inputlineno);
731         /*
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.
735          */
736         start_p = gs_p;
737         for (;;) {
738                 /*
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.
742                  */
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;
748                 }
749                 if (start_p == 0)       /* get out if no more this measure */
750                         break;
751
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;
756                         continue;
757                 }
758
759                 /*
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.
766                  */
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)
771                                 end_p->stemdir = UP;
772                 }
773                 if (end_p == 0)
774                         pfatal("beamed group is not terminated");
775
776                 /* handle this bunch of groups, and point at next */
777                 dobunch(start_p, end_p->next);
778                 start_p = end_p->next;
779         }
780 }
781 \f
782 /*
783  * Name:        setopstem()
784  *
785  * Abstract:    Sets stemdir for v1 or v2 groups for V_2OPSTEM/V_3OPSTEM.
786  *
787  * Returns:     void
788  *
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.
796  */
797
798 static void
799 setopstem(gs1_p, gs2_p)
800
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 */
803
804 {
805         debug(32, "setopstem file=%s line=%d", gs1_p->inputfile,
806                         gs1_p->inputlineno);
807         /* mark first voice's stems up */
808         while (gs1_p != 0) {
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) {
816                                         gs1_p->stemdir = UP;
817                                 }
818                         } else if (gs1_p->beamloc == STARTITEM) {
819                                 /* do same for all groups in beamed set */
820                                 setbeamedstem(gs1_p, UP);
821                         }
822                 }
823                 gs1_p = gs1_p->next;
824         }
825
826         /* mark second voice's stems down */
827         while (gs2_p != 0) {
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;
836                                 }
837                         } else if (gs2_p->beamloc == STARTITEM) {
838                                 /* do same for all groups in beamed set */
839                                 setbeamedstem(gs2_p, DOWN);
840                         }
841                 }
842                 gs2_p = gs2_p->next;
843         }
844 }
845 \f
846 /*
847  * Name:        setfreestem()
848  *
849  * Abstract:    Sets stemdir for each group in 2 linked lists for V_2FREESTEM.
850  *
851  * Returns:     void
852  *
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
857  *              voice has a space.
858  */
859
860 static void
861 setfreestem(gs1_p, gs2_p)
862
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 */
865
866 {
867         debug(32, "setfreestem file=%s line=%d", gs1_p->inputfile,
868                         gs1_p->inputlineno);
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);
872 }
873 \f
874 /*
875  * Name:        set1freestem()
876  *
877  * Abstract:    Sets stemdir for v1 or v2 groups for V_2FREESTEM/V_3FREESTEM.
878  *
879  * Returns:     void
880  *
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).
888  */
889
890 static void
891 set1freestem(this_p, other_p, stemdir)
892
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 */
898
899 {
900         register struct GRPSYL *start_p, *end_p; /* first and last of a set */
901         RATIONAL vtime, vtime2;         /* elapsed time this measure */
902
903
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 */
907
908         /*
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.
912          */
913         start_p = this_p;
914         for (;;) {
915                 /*
916                  * Find next group that has nongrace notes, accumulating
917                  * elapsed time.  This code depends on grace notes having
918                  * zero duration.
919                  */
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;
924                 }
925                 if (start_p == 0)       /* get out if no more this measure */
926                         break;
927
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);
931
932                         if (hasspace(other_p, vtime, vtime2)) {
933                                 /* other voice has space; decide stem */
934                                 dobunch(start_p, start_p->next);
935                         } else {
936                                 /*
937                                  * The other voice has notes/rests; force the
938                                  * the direction, unless the user has already
939                                  * forced it.
940                                  */
941                                 if (start_p->stemdir == UNKNOWN) {
942                                         start_p->stemdir = (short)stemdir;
943                                 }
944                         }
945
946                         start_p = start_p->next;
947                         vtime = vtime2;
948                         continue;
949                 }
950
951                 /* find end of this beamed group, ignoring grace groups */
952                 vtime2 = vtime;
953                 for (end_p = start_p; end_p != 0 &&
954                 (end_p->grpvalue == GV_ZERO || end_p->beamloc != ENDITEM);
955                 end_p = end_p->next)
956                         vtime2 = radd(vtime2, end_p->fulltime);
957                 if (end_p == 0)
958                         pfatal("beamed group is not terminated");
959                 vtime2 = radd(vtime2, end_p->fulltime); /* add in final note */
960
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);
965                 } else {
966                         /* other voice has notes/rests; this forces ours */
967                         setbeamedstem(start_p, stemdir);
968                 }
969
970                 vtime = vtime2;
971                 start_p = end_p->next;
972         }
973 }
974 \f
975 /*
976  * Name:        setbeamedstem()
977  *
978  * Abstract:    Sets stem direction in beamed set, favoring one direction.
979  *
980  * Returns:     void
981  *
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.
986  */
987
988 static void
989 setbeamedstem(start_p, stemdir)
990
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 */
993
994 {
995         struct GRPSYL *g_p;             /* point into the set */
996         int forcedir;                   /* direction forced by user */
997
998
999         forcedir = UNKNOWN;             /* no forcing yet */
1000
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) {
1005                         continue;
1006                 }
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 */
1017                         }
1018                 }
1019                 if (g_p->beamloc == ENDITEM) {
1020                         break;
1021                 }
1022         }
1023
1024         /* if user forced any stems, we'll go with that direction */
1025         if (forcedir != UNKNOWN) {
1026                 stemdir = forcedir;
1027         }
1028
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) {
1032                         continue;
1033                 }
1034                 g_p->stemdir = stemdir;
1035                 if (g_p->beamloc == ENDITEM) {
1036                         break;
1037                 }
1038         }
1039 }
1040 /*
1041  * Name:        dobunch()
1042  *
1043  * Abstract:    Sets stem direction for a single group or a beamed set.
1044  *
1045  * Returns:     void
1046  *
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.
1051  */
1052
1053 static void
1054 dobunch(start_p, end_p)
1055
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 */
1058
1059 {
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 */
1067
1068
1069         /*
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.
1081          */
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) {
1085                 /*
1086                  * Consider only note groups.  Cross staff beaming can have
1087                  * spaces in the list of groups, and rests need to be skipped.
1088                  */
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,
1095                                         gs_p->inputlineno,
1096                                         "cannot have both 'up' and 'down' stem in same set of beamed or 'alt'-ed note groups");
1097                                         stemdir = gs_p->stemdir;
1098                                 }
1099                         }
1100
1101                         if (gs_p->nnotes == 1) {
1102                                 lonesum += gs_p->notelist[0].stepsup;
1103                         } else {
1104                                 topsum += gs_p->notelist[0].stepsup;
1105                                 botsum += gs_p->notelist[ gs_p->nnotes - 1 ].
1106                                                 stepsup;
1107                         }
1108
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;
1112                         }
1113                 }
1114         }
1115
1116         /*
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.
1122          *
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.
1131          */
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 */
1137                                 stemdir = UP;
1138                                 break;
1139                         case CS_BELOW:          /* bm with staff below */
1140                                 stemdir = DOWN;
1141                                 break;
1142                         case CS_SAME:           /* no cross staff beaming */
1143                                 /* normal case: base on note distances */
1144                                 if (lonesum + topsum + botsum > 0)
1145                                         stemdir = DOWN;
1146                                 else if (lonesum + topsum + botsum < 0)
1147                                         stemdir = UP;
1148                                 else
1149                                         stemdir = insum >= 0 ? DOWN : UP;
1150                                 break;
1151                         }
1152                 }
1153         } else if (is_tab_staff(start_p->staffno) == YES) {
1154                 stemdir = DOWN;
1155         } else {
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");
1159                 if (stemdir == UP)
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 */
1163         }
1164
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;
1169         }
1170 }
1171 \f
1172 /*
1173  * Name:        dograce()
1174  *
1175  * Abstract:    Sets stem direction for a single grace group.
1176  *
1177  * Returns:     void
1178  *
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
1186  *              going either way.
1187  */
1188
1189 static void
1190 dograce(gs1_p, gs2_p)
1191
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 */
1194
1195 {
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};
1199
1200
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)
1204                         gs_p->stemdir = UP;
1205         }
1206
1207         /*
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.
1212          */
1213         vtime = Zero;
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);
1217                 } else {
1218                         /* does other voice have space? */
1219                         if (hasspace(gs1_p, vtime, radd(vtime, tiny)) == YES) {
1220                                 gs_p->stemdir = UP;
1221                         } else {
1222                                 gs_p->stemdir = DOWN;
1223                         }
1224                 }
1225         }
1226 }
1227 \f
1228 /*
1229  * Name:        setv3stem()
1230  *
1231  * Abstract:    Sets stem direction for each group in a linked list for voice 3.
1232  *
1233  * Returns:     default stem direction after this measure
1234  *
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.
1238  */
1239
1240 static int
1241 setv3stem(gs_p, stemdir)
1242
1243 struct GRPSYL *gs_p;    /* starts pointing at the first GRPSYL in a list */
1244 int stemdir;            /* stem direction of the previous group */
1245
1246 {
1247         register struct GRPSYL *start_p, *end_p; /* first and last of a set */
1248
1249
1250         debug(32, "setv3stem file=%s line=%d", gs_p->inputfile,
1251                         gs_p->inputlineno);
1252         /*
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.
1256          */
1257         start_p = gs_p;
1258         for (;;) {
1259                 /*
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.
1263                  */
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;
1269                 }
1270                 if (start_p == 0)       /* get out if no more this measure */
1271                         break;
1272
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;
1277                         continue;
1278                 }
1279
1280                 /*
1281                  * Find end of this beamed group, setting grace groups UP.
1282                  * Note that voice 3 does not allow cross staff beaming.
1283                  */
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;
1289                 }
1290                 if (end_p == 0)
1291                         pfatal("beamed group is not terminated");
1292
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;
1296         }
1297
1298         return (stemdir);
1299 }
1300 \f
1301 /*
1302  * Name:        dov3bunch()
1303  *
1304  * Abstract:    Sets stem dir for a single group or a beamed set on voice 3.
1305  *
1306  * Returns:     stem direction that was chosen
1307  *
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.
1311  */
1312
1313 static int
1314 dov3bunch(start_p, end_p, stemdir)
1315
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 */
1319
1320 {
1321         register struct GRPSYL *gs_p;   /* point along list of them */
1322         int userdir;                    /* stemdir requested by user */
1323
1324
1325         /*
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.
1329          */
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,
1340                                         gs_p->inputlineno,
1341                                         "cannot have both 'up' and 'down' stem in same set of beamed or 'alt'-ed note groups");
1342                                         userdir = gs_p->stemdir;
1343                                 }
1344                         }
1345                 }
1346         }
1347
1348         /* if user requested a direction, we will use that, else keep previous*/
1349         if (userdir != UNKNOWN)
1350                 stemdir = userdir;
1351
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;
1356         }
1357
1358         return (stemdir);
1359 }
1360 \f
1361 /*
1362  * Name:        setheads()
1363  *
1364  * Abstract:    Set headshape, headfont, headchar, and coords for all notes.
1365  *
1366  * Returns:     void
1367  *
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
1373  *              would be known.
1374  */
1375
1376 static void
1377 setheads()
1378
1379 {
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 */
1389
1390
1391         debug(16, "setheads");
1392         initstructs();                  /* clean out old SSV info */
1393
1394         /* just in case we'll need it later */
1395         allx_hsi = get_shape_num("allx");
1396
1397         /*
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.
1401          */
1402         for (mainll_p = Mainllhc_p; mainll_p != 0; mainll_p = mainll_p->next) {
1403
1404                 if (mainll_p->str == S_SSV) {
1405                         /* apply the SSV and go to the next item */
1406                         asgnssv(mainll_p->u.ssv_p);
1407                         continue;
1408                 }
1409
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])) {
1414                         continue;
1415                 }
1416
1417                 /*
1418                  * We found a staff to work on.  Set up some variables we'll
1419                  * be needing.
1420                  */
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;
1424
1425                 /*
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,
1428                  * but that's okay.
1429                  */
1430                 sharps = eff_key(staff_p->staffno);
1431                 keylet = Circle[(sharps + 1 + 7) % 7];
1432
1433                 /* loop through every possible voice on this staff */
1434                 for (vidx = 0; vidx < MAXVOICES; vidx++) {
1435
1436                         /* point at array of headshapes for this voice */
1437                         shapes = vvpath(staff_p->staffno, vidx + 1,
1438                                         NOTEHEADS)->noteheads;
1439
1440                         setvoiceheads(mainll_p, staff_p->groups_p[vidx],
1441                                 stafflines, shapes, is_tab, allx_hsi, sharps,
1442                                 keylet);
1443                 }
1444         }
1445 }
1446 \f
1447 /*
1448  * Name:        setvoiceheads()
1449  *
1450  * Abstract:    Set headshape, headfont, headchar, and coords for one GRPSYL.
1451  *
1452  * Returns:     void
1453  *
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
1458  *              the group.
1459  */
1460
1461 static void
1462 setvoiceheads(mll_p, gs_p, stafflines, shapes, is_tab, allx_hsi, sharps, keylet)
1463
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 */
1472
1473 {
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 */
1482
1483
1484         /* loop through every GRPSYL in voice (may be none) */
1485         for ( ; gs_p != 0; gs_p = gs_p->next) {
1486
1487                 /* we only care about notes, not rest/space */
1488                 if (gs_p->grpcont != GC_NOTES) {
1489                         continue;
1490                 }
1491
1492                 bendheight = 0;         /* init to no bends */
1493                 havebend = NO;
1494
1495                 /*
1496                  * Loop through every note in the GRPSYL, setting its
1497                  * headshape, head font/char, and coords.
1498                  */
1499                 for (n = 0; n < gs_p->nnotes; n++) {
1500
1501                         /* if there is no note-level override... */
1502                         if (gs_p->notelist[n].headshape == HS_UNKNOWN) {
1503
1504                                 /* set to group-level override if present */
1505                                 gs_p->notelist[n].headshape = gs_p->headshape;
1506
1507                                 /*
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.
1513                                  */
1514                                 if (gs_p->notelist[n].headshape == HS_UNKNOWN) {
1515
1516                                         if (is_tab) {
1517                                                 i = 0;  /* arbitrary */
1518                                         } else {
1519                                                 i = (gs_p-> notelist[n].letter
1520                                                         + 7 - keylet) % 7;
1521                                         }
1522
1523                                         gs_p->notelist[n].headshape = shapes[i];
1524                                 }
1525                         }
1526
1527                         /*
1528                          * Now that we know the stepsup (set in locllnotes())
1529                          * and the headshape, we can set the note's coords.
1530                          */
1531                         if (is_tab && gs_p->notelist[n].headshape != allx_hsi) {
1532
1533                                 /* handle tab (except when it's an X) */
1534
1535                                 gs_p->notelist[n].c[RY] = gs_p->notelist[n].
1536                                         stepsup * TABRATIO * STEPSIZE;
1537
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];
1544                                 } else {
1545                                         /*
1546                                          * Set vertical coordinates of the
1547                                          * "note" (fret number).  It is to be
1548                                          * centered on the appropriate line.
1549                                          */
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;
1556                                 }
1557
1558                         } else {
1559
1560                                 /* handle non-tab and tab X-notes */
1561
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;
1567
1568                                 /* half the height of the note head */
1569                                 vhalf = height(hfont, gs_p->notelist[n].notesize
1570                                         == GS_NORMAL ? DFLT_SIZE : SMALLSIZE,
1571                                         hchar) / 2;
1572
1573                                 /*
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.
1579                                  */
1580                                 stepsup = gs_p->notelist[n].stepsup;
1581                                 switch (gs_p->stemto) {
1582                                 case CS_ABOVE:
1583                                         if (n <= gs_p->stemto_idx) {
1584                                                 stepsup -= CSS_STEPS;
1585                                         }
1586                                         break;
1587                                 case CS_BELOW:
1588                                         if (n >= gs_p->stemto_idx) {
1589                                                 stepsup += CSS_STEPS;
1590                                         }
1591                                         break;
1592                                 }
1593                                 gs_p->notelist[n].c[RY] = stepsup * STEPSIZE *
1594                                         (is_tab ? TABRATIO : 1.0);
1595
1596                                 gs_p->notelist[n].c[RN] =
1597                                         gs_p->notelist[n].c[RY] + vhalf;
1598
1599                                 gs_p->notelist[n].c[RS] =
1600                                         gs_p->notelist[n].c[RY] - vhalf;
1601                         }
1602
1603                         if (is_tab) {
1604                                 /*
1605                                  * If there was a real bend, add to total height
1606                                  * of the bend numbers.
1607                                  */
1608                                 if (HASREALBEND(gs_p->notelist[n])) {
1609                                         bendheight += strheight(bend_string(
1610                                                 &gs_p->notelist[n])) + STDPAD;
1611                                 }
1612
1613                                 /* if any bend at all, remember it */
1614                                 if (HASBEND(gs_p->notelist[n])) {
1615                                         havebend = YES;
1616                                 }
1617                         }
1618                 }
1619
1620                 /*
1621                  * Set the group's coords.
1622                  */
1623                 if (is_tab) {
1624                         /*
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.
1630                          */
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;
1637                         }
1638
1639                         /*
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.
1643                          */
1644                         if (gs_p->nnotes == 0) {        /* no frets present */
1645                                 gs_p->c[RS] = 0;
1646                         } else {                        /* frets present */
1647                                 gs_p->c[RS] = gs_p->notelist
1648                                         [ gs_p->nnotes - 1 ].c[RS] - STDPAD;
1649                         }
1650
1651                         /* if bends, do work between this and other groups */
1652                         if (bendheight > 0) {
1653                                 intertab(gs_p, mll_p);
1654                         }
1655                 } else {
1656                         /*
1657                          * Non-tab: use the outermost non-CSS notes, but pad.
1658                          * If all notes are CSS, then set RN and RS to zero.
1659                          */
1660                         switch (gs_p->stemto) {
1661                         case CS_SAME:
1662                                 gs_p->c[RN] = gs_p->notelist
1663                                         [0].c[RN] + STDPAD;
1664                                 gs_p->c[RS] = gs_p->notelist
1665                                         [gs_p->nnotes-1].c[RS] - STDPAD;
1666                                 break;
1667                         case CS_ABOVE:
1668                                 if (gs_p->stemto_idx == gs_p->nnotes - 1) {
1669                                         gs_p->c[RN] = gs_p->c[RS] = 0.0;
1670                                 } else {
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;
1675                                 }
1676                                 break;
1677                         case CS_BELOW:
1678                                 if (gs_p->stemto_idx == 0) {
1679                                         gs_p->c[RN] = gs_p->c[RS] = 0.0;
1680                                 } else {
1681                                         gs_p->c[RN] = gs_p->notelist
1682                                            [0].c[RN] + STDPAD;
1683                                         gs_p->c[RS] = gs_p->notelist
1684                                            [gs_p->stemto_idx-1].c[RS] - STDPAD;
1685                                 }
1686                                 break;
1687                         }
1688                 }
1689         }
1690 }
1691 \f
1692 /*
1693  * Name:        fixoneline()
1694  *
1695  * Abstract:    Fix stemsup and vertical coord for notes on one-line staffs.
1696  *
1697  * Returns:     void
1698  *
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.
1704  */
1705
1706 static void
1707 fixoneline()
1708
1709 {
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 */
1714
1715
1716         debug(16, "fixoneline");
1717         initstructs();                  /* clean out old SSV info */
1718
1719         /*
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.
1722          */
1723         for (mainll_p = Mainllhc_p; mainll_p != 0; mainll_p = mainll_p->next) {
1724
1725                 if (mainll_p->str == S_SSV) {
1726                         /* apply the SSV and go to the next item */
1727                         asgnssv(mainll_p->u.ssv_p);
1728                         continue;
1729                 }
1730
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])) {
1735                         continue;
1736                 }
1737
1738                 staff_p = mainll_p->u.staff_p;
1739
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
1743                                 == TABCLEF) {
1744                         continue;
1745                 }
1746
1747                 /*
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
1750                  * anything to it.
1751                  */
1752                 for (v = 0; v < NORMVOICES && staff_p->groups_p[v] != 0; v++) {
1753
1754                         /* change stepsup from 0 only if notes not on the line*/
1755                         if (vvpath(staff_p->staffno, v + 1, ONTHELINE)->
1756                                         ontheline == YES) {
1757                                 continue;
1758                         }
1759
1760                         for (gs_p = staff_p->groups_p[v]; gs_p != 0;
1761                                         gs_p = gs_p->next) {
1762
1763                                 /* only notes are to be changed */
1764                                 if (gs_p->grpcont != GC_NOTES) {
1765                                         continue;
1766                                 }
1767
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;
1774                                 } else {
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;
1779                                 }
1780                         }
1781                 }
1782         }
1783 }