chiark / gitweb /
Import upstream version 5.3.
[mup] / mup / mup / prntdata.c
1
2 /* Copyright (c) 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006 by Arkkra Enterprises */
3 /* All rights reserved */
4
5 /* functions for printing things off of STAFF structs: notes, stems,
6  * rests, flags, beams, etc */
7
8 #include "defines.h"
9 #include "structs.h"
10 #include "globals.h"
11
12
13 /* This struct is used to build up a mesh that represents cross staff beams.
14  * This is used to figure out how far from the stem end to offset
15  * the end of a beam.
16  * There are a row of these linked horizontally via "next" for each beam.
17  * The stems are linked vertically via the above_p and below_p pointers.
18  * To get the stem offset for a given beam,
19  * the code finds the desired basictime on the appropriate stem,
20  * and counts how many beams that is from the end of the stem.
21  */
22 struct CSBINFO {
23         struct CSBINFO *next;           /* for next group in same beam */
24         struct CSBINFO *above_p;        /* beams above this beam */
25         struct CSBINFO *below_p;        /* beams below this beam */
26         struct GRPSYL *gs_p;            /* group this info is associated with.
27                                          * This is only used on the 8th beam,
28                                          * and is just for convenience,
29                                          * to save us from having to figure
30                                          * it out again later.
31                                          */
32         int basictime;                  /* 8, 16, 32, etc represented by beam */
33 };
34
35 /* static functions */
36 static void do_syl_joins P((char *syl, double west, double y));
37 static void pr_stuff P((struct STUFF *stufflist_p, int staffno,
38                 struct MAINLL *mll_p));
39 static int pr_grid P((struct STUFF *stuff_p, int staffnum));
40 static void pr_tieslur P((struct STUFF *stuff_p, struct MAINLL *mll_p,
41                 int staffno));
42 static int get_ts_style P((struct STUFF *stuff_p, struct MAINLL *mll_p));
43 static void pr_rest P((struct GRPSYL *gs_p, struct STAFF *staff_p));
44 static double mr_y_loc P((int staffno));
45 static void pr_note_dots P((struct NOTE *noteinfo_p, int numdots,
46                 double xdotr, double group_x, double group_y));
47 static void pr_parens P((struct NOTE *note_p, struct GRPSYL *gs_p));
48 static void pr_stems P((struct GRPSYL *grpsyl_p));
49 static double slash_xlen P((struct GRPSYL *grpsyl_p));
50 static void pr_flags P((struct GRPSYL *grpsyl_p, double x, double y));
51 static void pr_accidental P((struct NOTE *noteinfo_p, struct GRPSYL *grpsyl_p));
52 static void pr_leger P((struct NOTE *noteinfo_p, struct GRPSYL *gs_p,
53                 int staffno));
54 static int numlegers P((struct NOTE *noteinfo_p));
55 static double leger_length P((struct NOTE *noteinfo_p, struct GRPSYL *othergs_p,
56                 int lines, int other_is_prev, int is_intermediate));
57 static void pr_tupnums P((struct GRPSYL *gs_p, struct STAFF *staff_p));
58 static void pr_beams P((struct GRPSYL *grpsyl_p, int grpvalue, int grpsize));
59 static struct CSBINFO *mkcsbmesh P((struct GRPSYL *begin_p,
60                 struct GRPSYL *end_p));
61 static int draw_beams P((struct GRPSYL *gs_p, struct GRPSYL *endbeam_p,
62                 int basictime, int grpsize, int grpvalue));
63 static double beam_offset P((int nbeams, int gsize, int stemdir));
64 static struct GRPSYL *neighboring_note_beam_group P((struct GRPSYL *gs_p,
65                 struct GRPSYL *first_p, int backwards) );
66 static int chkgroupings P((int *side_p, struct GRPSYL *thisgs_p));
67 static void do_beam P((double x1, double y1, double x2, double y2,
68                 double halfwidth));
69 static void pr_cresc P((struct STUFF *stuff_p));
70 static void extend P((struct STUFF *stuff_p));
71 static int tupdir1voice P((struct GRPSYL *gs_p));
72 static int mirror P((char *str, int ch, int font));
73 \f
74
75 /* print things off of STAFF struct */
76
77 void
78 pr_staff(mll_p)
79
80 struct MAINLL *mll_p;   /* which main list struct holds the STAFF struct */
81
82 {
83         struct STAFF *staff_p;  /* mll_p->u.staff_p */
84         struct GRPSYL *grpsyl_p;/* current grpsyl */
85         struct MAINLL *barmll_p;/* to find TIMEDSSVs */
86         struct TIMEDSSV *tssv_p;/* for mid-measure parameter changes */
87         struct TIMEDSSV *t_p;   /* walk through the mid-measure changes */
88         RATIONAL now;           /* how far we are into measure */
89         char *savedlyr;         /* saved copy of lyric syllable */
90         register int n;         /* index thru notes in a group */
91         struct NOTE *noteinfo_p;/* current note */
92         int otherstaff;         /* staff number for cross-staff stems */
93         int v;                  /* walk through voices or verses on the staff */
94         int size;
95
96
97         debug(512, "pr_staff file=%s lineno=%d staff=%d", mll_p->inputfile,
98                         mll_p->inputlineno, mll_p->u.staff_p->staffno);
99
100         staff_p = mll_p->u.staff_p;
101
102         if ( svpath(staff_p->staffno, VISIBLE)->visible == NO) {
103                 /* invisible staffs are easy to print... */
104                 return;
105         }
106
107         /* do any syllables */
108         for (v = 0; v < staff_p->nsyllists; v++) {
109
110                 /* if bottom staff of "between" lyric is invisible,
111                  * the lyric silently disappears from output */
112                 if (staff_p->sylplace[v] == PL_BETWEEN &&
113                                 svpath(staff_p->staffno + 1, VISIBLE)->visible
114                                 == NO) {
115                         continue;
116                 }
117
118                 if (staff_p->syls_p[v] != (struct GRPSYL *) 0 &&
119                                         staff_p->syls_p[v]->inputlineno > 0) {
120                         /* tell PostScript about user input line reference */
121                         pr_linenum(staff_p->syls_p[v]->inputfile,
122                                         staff_p->syls_p[v]->inputlineno);
123                 }
124
125                 /* do all syllables for current verse/place */
126                 for (grpsyl_p = staff_p->syls_p[v];
127                                         grpsyl_p != (struct GRPSYL *) 0;
128                                         grpsyl_p = grpsyl_p->next) {
129
130                         if ( grpsyl_p->syl != (char *) 0) {
131
132                                 /* if <...> before or after syllable that
133                                  * were not used for placement, need to
134                                  * compensate for that */
135                                 lyr_compensate(grpsyl_p);
136
137                                 /* Extender printing can alter the lyrics
138                                  * string to get rid of the extender so it
139                                  * won't print with the syllable. But if we
140                                  * are printing pages using -o option we
141                                  * may need to have the original
142                                  * string preserved, because we may do this
143                                  * page again. So make a copy.
144                                  */
145                                 if ((savedlyr = malloc(strlen(grpsyl_p->syl) + 1))
146                                                         == 0) {
147                                         l_no_mem(__FILE__, __LINE__);
148                                 }
149                                 strcpy(savedlyr, grpsyl_p->syl);
150                                 
151                                 /* if syllable ends with a dash or underscore,
152                                  * they have to be spread between this syllable
153                                  * and the next */
154                                 (void) spread_extender(grpsyl_p, mll_p,
155                                                 grpsyl_p->vno,
156                                                 staff_p->sylplace[v], YES);
157
158                                 /* now print the syllable itself */
159                                 pr_string(grpsyl_p->c[AW], grpsyl_p->c[AY],
160                                                 grpsyl_p->syl, J_LEFT,
161                                                 grpsyl_p->inputfile,
162                                                 grpsyl_p->inputlineno);
163
164                                 /* handle multiple syllables on one chord */
165                                 do_syl_joins(grpsyl_p->syl,
166                                                 (double) grpsyl_p->c[AW],
167                                                 (double) grpsyl_p->c[AY]);
168                                 /* if string was altered, put original back */
169                                 if (strcmp(grpsyl_p->syl, savedlyr) != 0) {
170                                         FREE(grpsyl_p->syl);
171                                         grpsyl_p->syl = savedlyr;
172                                 }
173                                 else {
174                                         FREE(savedlyr);
175                                 }
176                         }
177                 }
178         }
179
180         /* Find the BAR that would point to any TIMEDSSVs for this measure. */
181         for (barmll_p = mll_p->next; barmll_p->str != S_BAR; barmll_p = barmll_p->next) {
182                 ;
183         }
184         t_p = tssv_p = barmll_p->u.bar_p->timedssv_p;
185
186         /* do notes, etc for each voice on the staff */
187         for (v = 0; v < MAXVOICES; v++) {
188
189                 if (staff_p->groups_p[v] == 0) {
190                         continue;
191                 }
192
193                 /* tab staff notes are handled differently */
194                 if (is_tab_staff(staff_p->staffno) == YES) {
195                         pr_tab_groups(staff_p->groups_p[v], mll_p);
196                         continue;
197                 }
198
199                 /* Set up to handle mid-measure changes, if any */
200                 if (tssv_p != 0) {
201                         setssvstate(mll_p);
202                 }
203                 t_p = tssv_p;
204                 now = Zero;
205
206                 /* for each GRPSYL in the list for current voice */
207                 for ( grpsyl_p = staff_p->groups_p[v];
208                                         grpsyl_p != (struct GRPSYL *) 0;
209                                         grpsyl_p = grpsyl_p->next) {
210
211                         /* Apply any timed SSVs */
212                         while (t_p != 0 && LE(t_p->time_off, now) ) {
213                                 asgnssv(&t_p->ssv);
214                                 t_p = t_p->next;
215                         }
216                         now = radd(now, grpsyl_p->fulltime);
217
218                         if (grpsyl_p->clef != NOCLEF) {
219                                 float widthclef;
220                                 int clefsize;
221                                 clefsize = (3 * DFLT_SIZE) / 4;
222                                 widthclef = width(FONT_MUSIC, clefsize,
223                                         clefchar(grpsyl_p->clef));
224                                 pr_clef(grpsyl_p->staffno,
225                                         grpsyl_p->c[AW] -
226                                         (widthclef + CLEFPAD) * Staffscale,
227                                         YES, clefsize);
228                         }
229                         if (grpsyl_p->grpcont == GC_SPACE) {
230                                 /* very easy to print a space -- do nothing! */
231                                 continue;
232                         }
233
234                         if (grpsyl_p->grpcont == GC_REST) {
235                                 pr_rest(grpsyl_p, staff_p);
236                                 continue;
237                         }
238
239                         if (is_mrpt(grpsyl_p) == YES) {
240                                 pr_mrpt(grpsyl_p, staff_p);
241                                 continue;
242                         }
243
244                         /* If group has a cross-staff stem,
245                          * figure out which is the other staff */
246                         if (grpsyl_p->stemto == CS_ABOVE) {
247                                 for (otherstaff = grpsyl_p->staffno - 1;
248                                                 otherstaff >= 1; otherstaff--) {
249                                         if (svpath(otherstaff, VISIBLE)->visible
250                                                         == YES) {
251                                                 break;
252                                         }
253                                 }
254                         }
255                         else if (grpsyl_p->stemto == CS_BELOW) {
256                                 for (otherstaff = grpsyl_p->staffno + 1;
257                                                 otherstaff <= Score.staffs;
258                                                 otherstaff++) {
259                                         if (svpath(otherstaff, VISIBLE)->visible
260                                                         == YES) {
261                                                 break;
262                                         }
263                                 }
264                         }
265                         else {
266                                 otherstaff = grpsyl_p->staffno;
267                         }
268                         if (otherstaff < 1 || otherstaff > Score.staffs) {
269                                 pfatal("failed to find other score for cross-staff stems for leger lines");
270                         }
271
272                         /* do each note in the group */
273                         for (n = 0; n < grpsyl_p->nnotes; n++) {
274
275                                 size = (grpsyl_p->notelist[n].notesize ==
276                                                 GS_NORMAL ? DFLT_SIZE :
277                                                 SMALLSIZE);
278
279                                 /* we're going to need the NOTE info a lot;
280                                  * get its address */
281                                 noteinfo_p = &(grpsyl_p->notelist[n]);
282
283                                 /* do the note head */
284                                 pr_muschar(noteinfo_p->c[AX],
285                                                 noteinfo_p->c[AY],
286                                                 noteinfo_p->headchar,
287                                                 size,
288                                                 noteinfo_p->headfont);
289                         
290                                 /* do any accidental */
291                                 pr_accidental(noteinfo_p, grpsyl_p);
292
293                                 /* do any dots */
294                                 pr_note_dots(noteinfo_p, grpsyl_p->dots,
295                                                 grpsyl_p->xdotr,
296                                                 (double) grpsyl_p->c[AX],
297                                                 (double) grpsyl_p->c[AY]);
298
299                                 /* print parentheses around note if any*/
300                                 if (noteinfo_p->note_has_paren == YES) {
301                                         pr_parens(noteinfo_p, grpsyl_p);
302                                 }
303
304                                 /* print small curve for 1/4 bends */
305                                 if (noteinfo_p->smallbend == YES) {
306                                         float adjust;
307
308                                         /* may have to move slightly to avoid
309                                          * flag. This is true if group is an
310                                          * unbeamed, stem-up group of 8th note
311                                          * or shorter duration */
312                                         if (grpsyl_p->basictime >= 8 &&
313                                                         grpsyl_p->stemdir == UP
314                                                         && grpsyl_p->beamloc
315                                                         == NOITEM) {
316                                                 adjust = 2.0 * STEPSIZE;
317                                         }
318                                         else {
319                                                 adjust = STEPSIZE;
320                                         }
321                                         pr_sm_bend( (double)
322                                                 noteinfo_p->c[AE] + adjust,
323                                                 (double)
324                                                 noteinfo_p->c[AY] + 0.5 * STEPSIZE);
325                                 }
326
327                                 /* do any leger lines */
328                                 if (grpsyl_p->stemto == CS_SAME ||
329                                                 (n >= FNNI(grpsyl_p) &&
330                                                 n <= LNNI(grpsyl_p) )) {
331                                         pr_leger(noteinfo_p, grpsyl_p,
332                                                         grpsyl_p->staffno);
333                                 }
334                                 else {
335                                         /* notes are on a different staff */
336                                         pr_leger(noteinfo_p, grpsyl_p,
337                                                         otherstaff);
338                                 }
339                         }
340
341                         /* do "with" lists */
342                         pr_withlist(grpsyl_p);
343
344                         /* do stems, flags, slash, and alt */
345                         pr_stems(grpsyl_p);
346
347                         /* print rolls */
348                         if (gets_roll(grpsyl_p, staff_p, v) == YES) {
349                                 print_roll(grpsyl_p);
350                         }
351                 }
352
353                 /* assign anything that happened after start of last group */
354                 while (t_p != 0) {
355                         asgnssv(&t_p->ssv);
356                         t_p = t_p->next;
357                 }
358
359                 /* print tuplet numbers if any */
360                 pr_tupnums(staff_p->groups_p[v], staff_p);
361
362                 /* draw beams */
363                 pr_beams(staff_p->groups_p[v], GV_NORMAL, GS_NORMAL);
364                 pr_beams(staff_p->groups_p[v], GV_ZERO, GS_SMALL);
365                 pr_beams(staff_p->groups_p[v], GV_NORMAL, GS_SMALL);
366         }
367
368         /* now do any associated STUFFs */
369         pr_stuff(staff_p->stuff_p, staff_p->staffno, mll_p);
370 }
371 \f
372
373 /* if two syllables are to be joined, draw a little curved line between them */
374
375 static void
376 do_syl_joins (syl, west, y)
377
378 char *syl;      /* syllable string */
379 double west;    /* where syllable was printed */
380 double y;       /* where syllable was printed */
381
382 {
383         int font, size;
384         char *p;                        /* pointer into syllable string */
385         float wid;                      /* of syllable up to space */
386         double x, east;                 /* of curved line */
387         double xinc, yinc;              /* increment to move when doing curve */
388         double spacewid;                /* width of ' ' */
389
390
391         int skipover = NO;
392         
393         /* skip past any <...> */
394         font = syl[0];
395         size = syl[1];
396         for (p = syl + 2; *p != '\0'; p++) {
397                 switch ( (unsigned) *p & 0xff) {
398                 case STR_PRE:
399                 case STR_U_PRE:
400                 case STR_PST:
401                 case STR_U_PST:
402                         skipover = YES;
403                         break;
404                 case STR_PRE_END:
405                 case STR_PST_END:
406                         skipover = NO;
407                         break;
408                 case STR_MUS_CHAR:
409                         p += 2;
410                         break;
411                 case STR_FONT:
412                         font = *(p+1);
413                         /*FALLTHRU*/
414                 case STR_SIZE:
415                 case STR_BACKSPACE:
416                 case STR_PAGENUM:
417                 case STR_NUMPAGES:
418                         p++;
419                         break;
420                 case ' ':
421                         if (skipover == NO && font <= EXT_FONT_OFFSET) {
422                                 /* temporarily shorten string to just before
423                                  * the space to get width of string up to
424                                  * that point */
425                                 *p = '\0';
426                                 wid = strwidth(syl);
427                                 *p = ' ';
428
429                                 /* Calculate dimensions
430                                  * and location of curve to be drawn. */
431                                 spacewid = width(font, size, ' ');
432                                 xinc = spacewid * 0.3;
433                                 yinc = spacewid * 0.15;
434                                 x = west + wid - STDPAD;
435                                 east = x + spacewid;
436
437                                 do_linetype(L_NORMAL);
438                                 do_moveto(x, y);
439                                 do_curveto(x + xinc, y - yinc,
440                                         east - xinc, y - yinc, east, y);
441                         }
442                         break;
443                 default:
444                         break;
445                 }
446         }
447 }
448 \f
449
450 /* print things in STUFF list */
451
452 static void
453 pr_stuff (stufflist_p, staffno, mll_p)
454
455 struct STUFF *stufflist_p;      /* which list of STUFF */
456 int staffno;                    /* which staff the stuff is for */
457 struct MAINLL *mll_p;
458
459 {
460         char lch;       /* last character in string */
461
462
463         /* do each item in stuff list */
464         for (   ; stufflist_p != (struct STUFF *) 0;
465                                         stufflist_p = stufflist_p->next) {
466
467                 set_staffscale( (stufflist_p->all == YES) ? 0 : staffno);
468
469                 switch (stufflist_p->stuff_type) {
470
471                 case ST_MUSSYM:
472                 case ST_OCTAVE:
473                 case ST_ROM:
474                 case ST_BOLD:
475                 case ST_ITAL:
476                 case ST_BOLDITAL:
477                         /* do 'til' clause if any */
478                         extend(stufflist_p);
479
480                         /* if special case of ending in ~ or _, don't print the
481                          * ~ or _ itself */
482                         if ((lch = last_char(stufflist_p->string)) == '~' ||
483                                         lch == '_') {
484                                 stufflist_p->string[strlen(stufflist_p->string)
485                                                 -1] = '\0';
486                         }
487
488                         /* print the string at specified place */
489                         if (stufflist_p->string != (char *) 0) {
490
491
492                                 /* print grid if appropriate,
493                                  * otherwise just the string. */
494                                 if (stufflist_p->modifier != TM_CHORD ||
495                                                 svpath(staffno, GRIDSWHEREUSED)
496                                                 ->gridswhereused == NO ||
497                                                 pr_grid(stufflist_p,
498                                                 (stufflist_p->all == YES ?
499                                                 0 : staffno))
500                                                 == NO) {
501                                         pr_string (stufflist_p->c[AW],
502                                                 stufflist_p->c[AY],
503                                                 stufflist_p->string, J_LEFT,
504                                                 stufflist_p->inputfile,
505                                                 stufflist_p->inputlineno);
506                                 }
507                         }
508
509                         break;
510
511                 case ST_CRESC:
512                 case ST_DECRESC:
513                         pr_cresc(stufflist_p);
514                         break;
515
516                 case ST_PEDAL:
517                         pr_ped_char(stufflist_p, staffno);
518                         break;
519
520                 case ST_PHRASE:
521                         pr_phrase(stufflist_p->crvlist_p, stufflist_p->modifier,
522                                 (stufflist_p->modifier == L_NORMAL ? YES : NO),
523                                 staffno);
524                         break;
525
526                 case ST_TIESLUR:
527                         pr_tieslur(stufflist_p, mll_p, staffno);
528                         break;
529                 
530                 case ST_BEND:
531                         pr_bend(stufflist_p->crvlist_p);
532                         break;
533
534                 case ST_TABSLUR:
535                         pr_tabslur(stufflist_p->crvlist_p,
536                                         get_ts_style(stufflist_p, mll_p));
537                         break;
538
539                 case ST_MIDI:
540                         break;
541
542                 default:
543                         pfatal("unknown stuff type");
544                         break;
545                 }
546         }
547 }
548 \f
549
550 /* Print a guitar grid. Return YES if grid was found and printed, else NO. */
551
552 static int
553 pr_grid(stuff_p, staffnum)
554
555 struct STUFF *stuff_p;
556 int staffnum;
557
558 {
559         struct GRID *grid_p;
560         double space;
561         float north, south;
562
563
564         if ((grid_p = findgrid(stuff_p->string)) == 0) {
565                 /* placement phase should have printed a warning already */
566                 return(NO);
567         }
568
569         /* print the grid name */
570         pr_string(stuff_p->c[AX] - strwidth(grid_p->name) / 2.0,
571                         stuff_p->c[AY], grid_p->name, J_LEFT,
572                         stuff_p->inputfile, stuff_p->inputlineno);
573
574         space = gridspace(staffnum);
575         gridsize(grid_p, staffnum, &north, &south, (float *) 0, (float *) 0);
576
577         do_grid(stuff_p->c[AX] - space * (grid_p->numstr - 1) / 2.0,
578                         stuff_p->c[AS] - south,
579                         space, grid_p, staffnum);
580         return(YES);
581 }
582 \f
583
584 /* print ties and slurs */
585
586 static void
587 pr_tieslur(stuff_p, mll_p, staffno)
588
589 struct STUFF *stuff_p;
590 struct MAINLL *mll_p;
591 int staffno;
592
593 {
594         int ts_style;           /* tie/slur style (L_DOTTED or L_DASHED) */
595
596
597         ts_style = get_ts_style(stuff_p, mll_p);
598
599         /* If tabslur, do that */
600         if ( stuff_p->curveno >= 0 && stuff_p->begnote_p->nslurto > 0
601                         && IS_NOWHERE(stuff_p-> begnote_p->slurtolist
602                         [stuff_p->curveno].octave)) {
603                 pr_tabslur(stuff_p->crvlist_p, ts_style);
604                 return;
605         }
606
607         /* print a regular tie/slur curve */
608         pr_phrase(stuff_p->crvlist_p, ts_style,
609                                 (ts_style == L_NORMAL ? YES : NO), staffno );
610 }
611 \f
612
613 /* given a TIESLUR STUFF, return the line type to use for it */
614
615 static int
616 get_ts_style(stuff_p, mll_p)
617
618 struct STUFF *stuff_p;
619 struct MAINLL *mll_p;
620
621 {
622         struct GRPSYL *prevgrp_p;       /* for carryins */
623         int n;                          /* notelist index */
624
625
626         if (stuff_p->carryin == YES) {
627                 prevgrp_p = prevgrpsyl(stuff_p->beggrp_p, &mll_p);
628                 if (stuff_p->curveno >= 0) {
629                         /* a carried-in slur. Need to find a note
630                          * in previous group that is slurred to this one,
631                          * and use its slurstyle. There is some chance
632                          * that there could be more than one slur to this
633                          * note from the same curveno
634                          * and each slur could have a different style,
635                          * in which case we no longer have enough information
636                          * to know which to use, so we just use the first
637                          * we find. */
638                         for (n = 0; n < prevgrp_p->nnotes; n++) {
639
640                                 if (prevgrp_p->notelist[n].nslurto
641                                                         <= stuff_p->curveno) {
642                                         /* couldn't have come from this grp */
643                                         continue;
644                                 }
645
646                                 if (prevgrp_p->notelist[n].slurtolist
647                                                 [stuff_p->curveno].letter
648                                                 == stuff_p->begnote_p->letter
649                                                 && prevgrp_p->notelist[n]
650                                                 .slurtolist[stuff_p->curveno].octave
651                                                 == stuff_p->begnote_p->octave) {
652
653                                         return (prevgrp_p->notelist[n].
654                                                 slurtolist[stuff_p->curveno]
655                                                 .slurstyle);
656                                 }
657                         }
658                 }
659                 else {
660                         /* a carried-in tie. Need to find matching note
661                          * in previous group, and use its tiestyle. */
662                         for (n = 0; n < prevgrp_p->nnotes; n++) {
663                                 if (prevgrp_p->notelist[n].letter ==
664                                                 stuff_p->begnote_p->letter &&
665                                                 prevgrp_p->notelist[n].octave
666                                                 == stuff_p->begnote_p->octave) {
667                                         return(prevgrp_p->notelist[n].tiestyle);
668                                 }
669                         }
670                 }
671         }
672
673         else {
674                 if (stuff_p->curveno >= 0) {
675                         /* a non-carried-in slur, use slurstyle */
676                         return(stuff_p->begnote_p->slurtolist
677                                                 [stuff_p->curveno].slurstyle);
678                 }
679                 else {
680                         /* a non-carried-in tie, use tiestyle */
681                         return(stuff_p->begnote_p->tiestyle);
682                 }
683         }
684
685         /* if none of those cases applied, use normal */
686         return(L_NORMAL);
687 }
688 \f
689
690 /* print a rest symbol */
691
692 static void
693 pr_rest(gs_p, staff_p)
694
695 struct GRPSYL *gs_p;    /* information about the rest to be printed */
696 struct STAFF *staff_p;
697
698 {
699         int muschar;    /* which type of rest character to print */
700         int d;          /* number of dots */
701         float adjust;   /* to space dots properly */
702         float y;        /* vertical location of rest */
703         int size;
704
705
706         if (gs_p->basictime < -1) {
707                 /* multirest are a special case */
708                 pr_multirest(gs_p, staff_p);
709                 return;
710         }
711
712         /* draw the rest */
713         muschar = restchar(gs_p->basictime);
714         /* Half and whole rests outside the staff need to use the version
715          * that includes a ledger line. So check for that case. 
716          * We used to use characters with ledgers all the time,
717          * but Ghostscript then sometimes seemed to misplace them
718          * by one pixel at certain magnifications, which looked bad. */
719         if (muschar == C_LL1REST || muschar == C_LL2REST) {
720                 double halfst;
721                 if (svpath(staff_p->staffno, STAFFLINES)->stafflines > 1) {
722                         halfst = halfstaffhi(staff_p->staffno);
723                 }
724                 else {
725                         halfst = 0.0;
726                 }
727                 /* The adjustments to halfst are chosen so that both half
728                  * and whole rests will properly get leger lines when they
729                  * are outside the staff, but not when inside.
730                  */
731                 if ( (gs_p->c[AN] > (staff_p->c[AY] + halfst + 1.7 * Stepsize)) ||
732                                 (gs_p->c[AN] < (staff_p->c[AY] - halfst - Stdpad)) ) {
733                         muschar = (muschar == C_LL1REST ? C_1REST : C_2REST);
734                 }
735         }
736         size = (gs_p->grpsize == GS_NORMAL ? DFLT_SIZE : SMALLSIZE);
737         if (gs_p->is_meas == YES) {
738                 /* measure rest is special case, have to move to middle */
739                 pr_muschar( (gs_p->c[AW] + gs_p->c[AE]) / 2.0,
740                                         gs_p->c[AY], muschar, size, FONT_MUSIC);
741         }
742         else {
743                 pr_muschar(gs_p->c[AX], gs_p->c[AY], muschar, size, FONT_MUSIC);
744         }
745
746         /* get ready to print any dots */
747         adjust = width(FONT_MUSIC, adj_size(size, Staffscale, (char *) 0,
748                                 -1), C_DOT) / 2.0;
749         y = _Cur[AY] + Stepsize;
750
751         /* print any dots after the rest */
752         for (d = 0; d < gs_p->dots; d++) {
753                 /* each time we print a dot, the current location will get
754                  * moved to just beyond that one */
755                 pr_muschar(_Cur[AX] + adjust + (2.0 * Stdpad), y, C_DOT, size,
756                                                                 FONT_MUSIC);
757         }
758 }
759 \f
760
761 /* print a measure repeat */
762
763 void
764 pr_mrpt(gs_p, staff_p)
765
766 struct GRPSYL *gs_p;
767 struct STAFF *staff_p;
768
769 {
770         double x;               /* horizontal position of number string */
771         double y, y_offset;     /* vertical location */
772         double height, width;   /* of meas num string */
773         char *numstr;           /* ASCII version of numbers of measures */
774
775
776         /* measure repeat has to be moved to the middle of the measure */
777         pr_muschar( (gs_p->c[AW] + gs_p->c[AE]) / 2.0,
778                 mr_y_loc(gs_p->staffno), C_MEASRPT, DFLT_SIZE, FONT_MUSIC);
779
780         if (svpath(gs_p->staffno, NUMBERMRPT)->numbermrpt == YES) {
781                 /* print number above the staff */
782                 y = Staffs_y[gs_p->staffno];
783                 numstr = mrnum(staff_p, &x, &y_offset, &height, &width);
784                 pr_string(x, y + y_offset, numstr, J_LEFT, (char *) 0, -1);
785         }
786 }
787 \f
788
789 /* given a staff number, return the y at which to print the measure repeat
790  * or multirest symbols. If the number of staff lines is odd, this is the
791  * middle line, otherwise the line just above the middle. */
792
793 static double
794 mr_y_loc(staffno)
795
796 int staffno;
797
798 {
799         double y;
800
801         y = Staffs_y[staffno];
802         /* if even number of staff lines, move up a stepsize */
803         if ( (svpath(staffno, STAFFLINES)->stafflines & 1) == 0) {
804                 y += Stepsize * (is_tab_staff(staffno) ? TABRATIO : 1.0);
805         }
806         return(y);
807 }
808 \f
809
810 /* print the dots for dotted notes */
811
812 static void
813 pr_note_dots(noteinfo_p, numdots, xdotr, group_x, group_y)
814
815 struct NOTE *noteinfo_p;        /* which note to dot */
816 int numdots;            /* how many dots to print */
817 double xdotr;           /* relative x distance from note to print the dots */
818 double group_x;
819 double group_y;         /* coord of group, dots are relative to this */
820
821 {
822         float adjust;   /* to place dots with proper spacing */
823
824
825         /* if note isn't dotted, nothing to do */
826         if (numdots <= 0) {
827                 return;
828         }
829
830         adjust = width(FONT_MUSIC, adj_size(DFLT_SIZE, Staffscale,
831                                 (char *) 0, -1), C_DOT) / 2.0;
832
833         /* go to where first dot belongs */
834         set_cur(group_x + xdotr - adjust, group_y + noteinfo_p->ydotr);
835         
836         /* print as many dots as necessary */
837         for (  ; numdots > 0; numdots--) {
838                 pr_muschar(_Cur[AX] + adjust + (2.0 * Stdpad),
839                                 _Cur[AY], C_DOT, DFLT_SIZE, FONT_MUSIC);
840         }
841 }
842 \f
843
844 /* print parentheses around a note. Should only be called if note_has_paren
845  * is YES */
846
847 static void
848 pr_parens(note_p, gs_p)
849
850 struct NOTE *note_p;
851 struct GRPSYL * gs_p;
852
853 {
854         char paren_string[4];
855         double y;
856
857
858         /* make a parentheses string of proper size in internal string format */
859         (void) sprintf(paren_string, "%c%c(", FONT_TR,
860                 adj_size((note_p->notesize == GS_NORMAL ? DFLT_SIZE : SMALLSIZE),
861                                 Staffscale, (char *) 0, -1));
862
863         /* center the parentheses vertically on the Y on the note */
864         y = note_p->c[AY] - (strascent(paren_string)
865                                         - (strheight(paren_string) / 2.0));
866
867         /* print the left parenthesis */
868         pr_string(gs_p->c[AX] + note_p->wlparen, y,
869                                 paren_string, J_LEFT, (char *) 0, -1);
870
871         /* now do the right parenthesis */
872         paren_string[2] = ')';
873         pr_string(gs_p->c[AX] + note_p->erparen - strwidth(paren_string), y,
874                                 paren_string, J_LEFT, (char *) 0, -1);
875 }
876 \f
877
878 /* print "with" lists */
879
880 void
881 pr_withlist(gs_p)
882
883 struct GRPSYL *gs_p;    /* GRPSYL that might have with lists */
884
885 {
886         float y;                /* where to start from */
887         float x;
888         float  y_offset, sign;
889         float x_offset;         /* to center first character of item on note */
890         float yposition;        /* y coordinate at which to print */
891         float item_height;      /* height of with list item */
892         int first_char;         /* first char of string to print */
893         char *str_p;            /* pointer into string to print */
894         int font, size;
895         int index;              /* offset into with list */
896         int alternate;          /* upside version of music symbol */
897         float ystaff;           /* y of middle of staff */
898         float yline;            /* y value of staff line */
899         float top, bot;         /* top and bottom of item to be printed */
900         float pad;              /* vertical padding around short items */
901         int sl;                 /* staff line index */
902         float adjusted_stepsize;        /* STEPSIZE or STEPSIZE * TABRATIO
903                                  * depending on whether tab staff or not */
904         int stafflines;         /* how many lines in current staff */
905         float minwithheight;    /* MINWITHHEIGHT * Staffscale */
906
907
908         if (gs_p->nnotes == 0) {
909                 return;
910         }
911
912         /* with goes forward from note opposite stem */
913         if (gs_p->normwith == YES) {
914                 if (gs_p->stemdir == UP) {
915                         y = gs_p->notelist [gs_p->nnotes - 1] .c[AS];
916                         x = gs_p->notelist [gs_p->nnotes - 1] .c[AX];
917                         sign = -1.0;
918                 }
919                 else {
920                         y = gs_p->notelist[0].c[AN];
921                         x = gs_p->notelist[0].c[AX];
922                         sign = 1.0;
923                 }
924         }
925         else {
926                 /* with goes on opposite side than normal */
927                 y = find_y_stem(gs_p);
928                 if (gs_p->stemdir == DOWN) {
929                         sign = -1.0;
930                         /* whole notes /double wholes may have
931                          * zero length stems so have to adjust */
932                         if (gs_p->stemlen <= 0.0) {
933                                 y = gs_p->notelist[gs_p->nnotes - 1] .c[AS];
934                         }
935                         /* beamed notes stems effective stick out a little
936                          * farther, so compensate for that */
937                         if (gs_p->beamloc != NOITEM) {
938                                 y -= POINT;
939                         }
940                 }
941                 else {
942                         sign = 1.0;
943                         if (gs_p->stemlen <= 0.0) {
944                                 y = gs_p->notelist[0].c[AN];
945                         }
946                         if (gs_p->beamloc != NOITEM) {
947                                 y += POINT;
948                         }
949                 }
950                 x = gs_p->c[AX];
951         }
952
953         /* If a dot, wedge, and uwedge is the only item in the list,
954          * and it's on the stem side of a group with a stem, it is supposed
955          * to be aligned with the stem. */
956         if (gs_p->normwith == NO && gs_p->nwith == 1 &&
957                                 gs_p->basictime > 1 && gs_p->stemlen > 0.0 &&
958                                 is_music_symbol(gs_p->withlist[0]) == YES) {
959                 font = gs_p->withlist[0][0];
960                 size = gs_p->withlist[0][1];
961                 str_p = gs_p->withlist[0] + 2;
962                 first_char = next_str_char(&str_p, &font, &size);
963                 if (first_char == C_DOT || first_char == C_WEDGE ||
964                                         first_char == C_UWEDGE) {
965                         x = find_x_stem(gs_p);
966                 }
967         }
968
969         y_offset = 0.0;
970         minwithheight = MINWITHHEIGHT * Staffscale;
971
972         /* do each item in with list */
973         for (index = 0; index < gs_p->nwith; index++) {
974
975                 /* should center first character on x */
976                 font = gs_p->withlist[index][0];
977                 size = gs_p->withlist[index][1];
978                 str_p = gs_p->withlist[index] + 2;
979                 first_char = next_str_char(&str_p, &font, &size);
980
981                 /* get upside down version if necessary */
982                 if (sign == -1.0 && IS_MUSIC_FONT(font)) {
983                         if ((alternate = mirror(gs_p->withlist[index],
984                                         first_char, font)) != first_char) {
985                                 *(str_p - 1) = (char) alternate;
986                         }
987                 }
988                 
989                 x_offset = left_width( &(gs_p->withlist[index][0]) );
990
991                 /* get height of item to print */
992                 item_height = strheight(gs_p->withlist[index]);
993
994                 /* if string is so short vertically
995                  * it could get swallowed up in a staff
996                  * line, adjust to fall in a space. Placement phase will have
997                  * allowed MINWITHHEIGHT, so put in middle of that area unless
998                  * that would fall on a line, in which case move somewhat */
999                 if (item_height < minwithheight) {
1000                         /* need to adjust this one. Start out by putting in
1001                          * middle vertically of reserved area */
1002                         yposition = y + y_offset + sign * minwithheight / 2.0;
1003
1004                         /* no reason to adjust further for 1-line staffs */
1005                         if ((stafflines = svpath(gs_p->staffno,
1006                                                 STAFFLINES)->stafflines) > 1) {
1007
1008                                 /* get stepsize distance based on whether it
1009                                  * is a tab staff or not */
1010                                 adjusted_stepsize = (is_tab_staff(gs_p->staffno)
1011                                         == YES ? Stepsize * TABRATIO : Stepsize);
1012
1013                                 /* find y of middle of staff */
1014                                 ystaff = gs_p->notelist[0].c[AY]
1015                                         - (gs_p->notelist[0].stepsup
1016                                         * adjusted_stepsize);
1017
1018                                 /* take the extra vertical space alloted to this
1019                                  * with list item, and add 1/4 of it on top
1020                                  * and bottom as padding. If no staff line is
1021                                  * in between the boundaries of the item after
1022                                  * adding that padding, it's good enough where
1023                                  * it is. Otherwise, if a staff line falls above
1024                                  * the middle of the item, move the item
1025                                  * down into space. Otherwise move it
1026                                  * up into space.
1027                                  */
1028                                 pad = (minwithheight - item_height) / 4.0;
1029                                 top = yposition + (item_height / 2.0) + pad;
1030                                 bot = yposition - (item_height / 2.0) - pad;
1031
1032                                 /* check each staff line for collisions, from
1033                                  * bottom to top */
1034                                 for (sl = -(stafflines - 1);
1035                                                 sl <= (stafflines - 1);
1036                                                 sl += 2) {
1037
1038                                         /* find y of current staff line */
1039                                         yline = ystaff + (sl * adjusted_stepsize);
1040
1041                                         /* check if current staff line goes
1042                                          * through the item
1043                                          * as currently placed */
1044                                         if (yline < top && yline > bot) {
1045                                                 /* collides--need to move */
1046
1047                                                 if ((top - yline) >
1048                                                                 (yline - bot)) {
1049                                                         /* move up to area
1050                                                          * above the line */
1051                                                         yposition += 2.0 * pad;
1052                                                         /* if overdid the move,
1053                                                          * move back a bit */
1054                                                         if (yposition - yline -
1055                                                         (item_height / 2.0)
1056                                                         > 0.7 * adjusted_stepsize) {
1057                                                                 yposition -=
1058                                                                  0.4 * adjusted_stepsize;
1059                                                         }
1060                                                 }
1061                                                 else {
1062                                                         /* move down to area
1063                                                          * below the line */
1064                                                         yposition -= 2.0 * pad;
1065                                                         if (yline - yposition -
1066                                                         (item_height / 2.0)
1067                                                         > 0.7 * adjusted_stepsize) {
1068                                                                 yposition +=
1069                                                                  0.4 * adjusted_stepsize;
1070                                                         }
1071                                                 }
1072
1073                                                 /* only 1 staff line can
1074                                                  * possibly interfere,
1075                                                  * and we've found that one, so
1076                                                  * can jump out of loop */
1077                                                 break;
1078                                         }
1079                                 }
1080                         }
1081
1082                         /* adjust y_offset to include the area taken by item */
1083                         y_offset += minwithheight * sign;
1084
1085                         /* up to now, we've been using the center of the item,
1086                          * so now adjust to baseline */
1087                         if (sign > 0.0) {
1088                                 yposition += (item_height / 2.0)
1089                                         - strascent(gs_p->withlist[index]);
1090                         }
1091                         else {
1092                                 yposition -= (item_height / 2.0)
1093                                         - strdescent(gs_p->withlist[index]);
1094                         }
1095                 }
1096                 else {
1097                         /* not too short, handle normally */
1098                         y_offset += item_height * sign;
1099                         yposition = y + y_offset;
1100
1101                         /* adjust to get to baseline of string from top or
1102                          * bottom that we've used up to this point */
1103                         if (sign > 0.0) {
1104                                 yposition -= strascent(gs_p->withlist[index]);
1105                         }
1106                         else {
1107                                 yposition += strdescent(gs_p->withlist[index]);
1108                         }
1109                 }
1110
1111                 pr_string(x - x_offset, yposition, gs_p->withlist[index],
1112                                 J_CENTER, gs_p->inputfile, gs_p->inputlineno);
1113         }
1114 }
1115 \f
1116
1117 /* print note stems and flags. Also print any slashes and alt lines */
1118
1119 static void
1120 pr_stems(grpsyl_p)
1121
1122 struct GRPSYL *grpsyl_p;        /* which group's stem to print */
1123
1124 {
1125         float x, y1, y2;
1126         float sign;     /* 1 or -1 direction for moving to draw slashes */
1127         float y_offset, offset, spacing;        /* for where to draw slashes */
1128         float y_tilt;           /* how much to move in y direction to get
1129                                  * proper tilt on slashes */
1130         float halfwidth;        /* half width of slash or alt line */
1131         struct GRPSYL *first_p, *last_p;        /* beginning and ending group
1132                                                  * of beam group */
1133         int grpsize;            /* grpsize field of grpsyl_p */
1134         int grpvalue;           /* grpvalue field of grpsyl_p */
1135         int slash;              /* to count number of slashes drawn */
1136         struct NOTE *note_p;
1137
1138
1139         /* if no stem, nothing to do */
1140         if ( grpsyl_p->stemlen <= 0 && grpsyl_p->slash_alt == 0) {
1141                 return;
1142         }
1143
1144         /* figure out x coordinate of stem */
1145         x = find_x_stem(grpsyl_p);
1146
1147         /* if stem is up, start at bottom note, if down, at top */
1148         if (grpsyl_p->stemdir == UP) {
1149                 note_p = &(grpsyl_p->notelist[ grpsyl_p->nnotes - 1]);
1150                 y1 = note_p->c[AY];
1151                 y2 = find_y_stem(grpsyl_p);
1152                 sign = -1;
1153         }
1154         else {
1155                 note_p = &(grpsyl_p->notelist [0]);
1156                 y1 = note_p->c[AY];
1157                 y2 = find_y_stem(grpsyl_p);
1158                 sign = 1;
1159         }
1160
1161         if (note_p->headchar != 0) {
1162                 y1 += stem_yoff(note_p->headchar, note_p->headfont,
1163                         grpsyl_p->stemdir)
1164                         * (note_p->notesize == GS_NORMAL
1165                         ? Stepsize : Stepsize * SM_FACTOR);
1166         }
1167
1168         if (grpsyl_p->basictime >= 2) {
1169                 /* print the stem */
1170                 do_linetype(L_NORMAL);
1171
1172                 draw_line(x, y1, x, y2);
1173
1174                 /* attach any flags as appropriate */
1175                 pr_flags(grpsyl_p, (double) x, (double) y2);
1176         }
1177
1178         /* print any slashes */
1179         if (grpsyl_p->slash_alt > 0) {
1180
1181                 /* adjust for flags or beams. */
1182                 if (grpsyl_p->basictime >= 8) {
1183                         offset = (numbeams(grpsyl_p->basictime) - 1) *
1184                                 (grpsyl_p->grpsize == GS_NORMAL ? 5.0 : 4.0)
1185                                 * Stdpad;
1186                         if (grpsyl_p->beamloc == NOITEM) {
1187                                 if (grpsyl_p->grpsize == GS_NORMAL) {
1188                                         offset += 8.0 * Stdpad;
1189                                 }
1190                                 else if (grpsyl_p->basictime != 16) {
1191                                         /* 16th small notes don't have any extra
1192                                          * stem to account for extra flag */
1193                                         offset += 3.0 * Stdpad;
1194                                 }
1195                         }
1196                 }
1197                 else {
1198                         offset = 0.0;
1199                 }
1200
1201                 if ( grpsyl_p->beamloc == NOITEM) {
1202                         /* unbeamed things get hard-coded tilt value */
1203                         if (grpsyl_p->grpvalue == GV_ZERO) {
1204                                 y_tilt = (grpsyl_p->stemdir == UP ? 3.5 : -3.5)
1205                                                         * Stdpad;
1206                         }
1207                         else {
1208                                 y_tilt = 2.2 * Stdpad;
1209                         }
1210                 }
1211
1212                 else {
1213                         /* beamed. Need to slant slashes the same as beam */
1214
1215                         grpsize = grpsyl_p->grpsize;
1216                         grpvalue = grpsyl_p->grpvalue;
1217
1218                         /* find beginning and ending stems */
1219                         for (first_p = grpsyl_p; (first_p->beamloc != STARTITEM)
1220                                         || (first_p->grpsize != grpsize)
1221                                         || (first_p->grpvalue != grpvalue);
1222                                         first_p = first_p->prev) {
1223                                 ;
1224                         }
1225
1226                         for (last_p = grpsyl_p; (last_p->beamloc != ENDITEM)
1227                                         || (last_p->grpsize != grpsize)
1228                                         || (last_p->grpvalue != grpvalue);
1229                                         last_p = last_p->next) {
1230                                 ;
1231                         }
1232
1233                         /* calculate slope from them. We find the ratio of
1234                          * y to x of the beam and apply that proportion to
1235                          * the known x length of the slash to get the y height
1236                          * of the slash, then divide by 2 to get the y distance
1237                          * on either side of the stem. */
1238                         y_tilt = (((find_y_stem(last_p) - find_y_stem(first_p))
1239                                         * (2.0 * slash_xlen(grpsyl_p)))
1240                                         / (find_x_stem(last_p)
1241                                         - find_x_stem(first_p))) / 2.0;
1242                         y1 = find_y_stem(first_p);
1243                 }
1244
1245                 /* draw the slashes */
1246                 pr_slashes(grpsyl_p, (double) x, (double) y2, (double) sign,
1247                                 (double) offset, (double) y_tilt);
1248         }
1249
1250         /* print alt group lines if any */
1251         if (grpsyl_p->slash_alt < 0) {
1252                 struct GRPSYL *grpsyl2_p;
1253                 float grp2x, grp2y;     /* stem of second group */
1254                 float grp1y_offset, grp2y_offset;
1255
1256
1257                 if (grpsyl_p->next == (struct GRPSYL *) 0) {
1258                         pfatal("missing second group in alt pair");
1259                 }
1260
1261                 /* figure out how wide to draw the lines and how far apart
1262                  * to make them */
1263                 if (grpsyl_p->grpsize == GS_NORMAL) {
1264                         halfwidth = W_WIDE * Staffscale / PPI / 2.0;
1265                         spacing = 5.0 * Stdpad;
1266                 }
1267                 else {
1268                         halfwidth = W_MEDIUM * Staffscale / PPI / 2.0;
1269                         spacing = 3.0 * Stdpad;
1270                 }
1271
1272                 /* find the stem coordinates of the second group */
1273                 grpsyl2_p = grpsyl_p->next;
1274                 grp2x = find_x_stem(grpsyl2_p);
1275                 grp2y = find_y_stem(grpsyl2_p);
1276
1277                 /* on notes shorter than half note, the lines don't go all the
1278                  * way to the stems */
1279                 if ( grpsyl_p->basictime >= 4) {
1280                         /* figure out where the y of the end of the line is
1281                          * by multiplying the x value by the tangent of the
1282                          * angle of the line that would go all the way
1283                          * between the stems */
1284                         grp2y_offset = (grp2x - x - (6.0 * Stdpad))
1285                                                 * ((grp2y - y2) / (grp2x - x));
1286                         grp1y_offset = (6.0 * Stdpad)
1287                                         * ((grp2y - y2) / (grp2x - x));
1288                         /* if 8th notes or shorter, get out of way of beams */
1289                         offset = numbeams(grpsyl_p->basictime) * spacing;
1290                         x += (6.0 * Stdpad);
1291                         grp2x -= (6.0 * Stdpad);
1292                 }
1293                 else {
1294                         grp1y_offset = 0.0;
1295                         grp2y_offset = grp2y - y2;
1296                         offset = 0.0;
1297                 }
1298
1299                 /* draw the alt lines */
1300                 for (slash = -(grpsyl_p->slash_alt) - 1; slash >= 0; slash--) {
1301                         y_offset = sign * slash * spacing + (sign * offset);
1302                         do_newpath();
1303                         do_moveto(x, y2 + y_offset + grp1y_offset - halfwidth);
1304                         do_line(x, y2 + y_offset + grp1y_offset + halfwidth);
1305                         do_line(grp2x, y2 + y_offset + grp2y_offset
1306                                                                 + halfwidth);
1307                         do_line(grp2x, y2 + y_offset + grp2y_offset
1308                                                                 - halfwidth);
1309                         do_closepath();
1310                         do_fill();
1311                 }
1312
1313                 /* earlier phase wanted both groups in alt pair to have
1314                  * slash_alt set, but now we've printed this one, so clear
1315                  * the one on the following group, so it won't try to
1316                  * print another alt group */
1317                 grpsyl2_p->slash_alt = 0;
1318         }
1319 }
1320 \f
1321
1322 void
1323 pr_slashes(grpsyl_p, x, y, sign, offset, y_tilt)
1324
1325 struct GRPSYL *grpsyl_p;
1326 double x;
1327 double y;
1328 double sign;
1329 double offset;
1330 double y_tilt;
1331
1332 {
1333         int slash;
1334         double xlen;
1335         float y_offset;
1336         float spacing;
1337         float halfwidth;
1338
1339
1340         /* get length based on note head size */
1341         xlen = slash_xlen(grpsyl_p);
1342
1343         /* figure out how wide to make the slashes and how far apart
1344         * to space them */
1345         if (grpsyl_p->grpsize == GS_NORMAL) {
1346                 halfwidth = W_WIDE * Staffscale / PPI / 2.0;
1347                 spacing = 5 * Stdpad;
1348         }
1349         else {
1350                 halfwidth = W_MEDIUM * Staffscale / PPI / 2.0;
1351                 spacing = 4 * Stdpad;
1352         }
1353
1354         for (slash = grpsyl_p->slash_alt; slash > 0; slash--) {
1355                 y_offset = y + sign * (offset + (spacing * slash));
1356
1357                 /* draw filled parallelogram */
1358                 do_newpath();
1359                 do_moveto(x - xlen, y_offset - y_tilt - halfwidth);
1360                 do_line(x - xlen, y_offset - y_tilt + halfwidth);
1361                 do_line(x + xlen, y_offset + y_tilt + halfwidth);
1362                 do_line(x + xlen, y_offset + y_tilt - halfwidth);
1363                 do_closepath();
1364                 do_fill();
1365         }
1366 }
1367
1368 static double
1369 slash_xlen(grpsyl_p)
1370
1371 struct GRPSYL *grpsyl_p;
1372
1373 {
1374         return (SLASHHORZ * Stepsize *
1375                         (grpsyl_p->grpsize == GS_NORMAL ? 1.0 : SM_FACTOR));
1376 }
1377 \f
1378
1379 /* print flags on 8th and shorter notes */
1380
1381 static void
1382 pr_flags(grpsyl_p, x, y)
1383
1384 struct GRPSYL *grpsyl_p;        /* group for which to draw flags */
1385 double x;
1386 double y;                       /* coord of end of stem */
1387
1388 {
1389         int muschar;    /* what kind of flag to print */
1390         float y_offset; /* from end of stem */
1391         int f;          /* how many flags */
1392         int size;
1393
1394
1395         /* only 8th and shorter notes might have flags */
1396         if (grpsyl_p->basictime < 8) {
1397                 return;
1398         }
1399
1400         /* if not a note, no flag */
1401         if (grpsyl_p->grpcont != GC_NOTES) {
1402                 return;
1403         }
1404
1405         /* if beamed, no flag */
1406         if (grpsyl_p->beamloc != NOITEM) {
1407                 return;
1408         }
1409
1410         /* figure out if up/down and whether small/reg */
1411         muschar = (grpsyl_p->stemdir == UP ? C_DNFLAG : C_UPFLAG);
1412         size = (grpsyl_p->grpsize == GS_NORMAL ? DFLT_SIZE : SMALLSIZE);
1413
1414         /* do for each flag. f == 1 less than the number of flags, and is
1415          * how much to multiply the y_offset by for each flag */
1416         for ( f = numbeams(grpsyl_p->basictime) - 1; f >= 0; f--) {
1417
1418                 switch (muschar) {
1419
1420                 case C_UPFLAG:
1421                         y_offset = f * (grpsyl_p->grpsize == GS_NORMAL ?
1422                                                 FLAGSEP : SMFLAGSEP);
1423                         break;
1424                 case C_DNFLAG:
1425                         y_offset = -f * (grpsyl_p->grpsize == GS_NORMAL ?
1426                                                 FLAGSEP : SMFLAGSEP);
1427                         break;
1428                 default:
1429                         pfatal("bad flag type");
1430                         /*NOTREACHED*/
1431                         return; /* to shut up compiler warning about unused */
1432                 }
1433
1434                 y_offset *= Staffscale;
1435
1436                 /* now that we know where to place the flag, print it */
1437                 pr_muschar(x + width(FONT_MUSIC,
1438                                 adj_size(size, Staffscale, (char *) 0, -1),
1439                                 muschar) / 2.0,
1440                                 y + y_offset, muschar, size, FONT_MUSIC);
1441         }
1442 }
1443 \f
1444
1445 /* print any accidental */
1446
1447 static void
1448 pr_accidental(noteinfo_p, grpsyl_p)
1449
1450 struct NOTE *noteinfo_p;        /* info about the note being printed */
1451 struct GRPSYL *grpsyl_p;        /* info about the group conatining the note */
1452
1453 {
1454         int muschar;    /* which accidental symbol to draw */
1455         int size;
1456         int a_size;     /* size adjusted for Staffscale */
1457
1458
1459         /* figure out which accidental symbol to use */
1460         muschar = acc2char(noteinfo_p->accidental);
1461
1462         /* if there is an accidental, print it at specified place */
1463         if (muschar != '\0') {
1464                 size = (noteinfo_p->notesize == GS_NORMAL
1465                                                 ? DFLT_SIZE : SMALLSIZE);
1466                 a_size = adj_size(size, Staffscale, (char *) 0, -1);
1467                 if (noteinfo_p->acc_has_paren == NO) {
1468                         pr_muschar(grpsyl_p->c[AX] + noteinfo_p->waccr
1469                                 + width(FONT_MUSIC, a_size, muschar) / 2.0,
1470                                 noteinfo_p->c[AY], muschar, size, FONT_MUSIC);
1471                 }
1472                 else {
1473                         /* have to print parentheses in addition to the
1474                          * symbol for the accidental */
1475                         char paren_string[4];   /* "(" or ")" in internal format */
1476                         double offset;          /* y adjustment of ( ) */
1477
1478                         /* create string for "(" */
1479                         (void) sprintf(paren_string, "%c%c%c",
1480                                                         FONT_TR, a_size, '(');
1481
1482                         /* to center things vertically on the note, need to
1483                          * adjust parentheses downward by difference between
1484                          * the ascent and half the height of the parenthesis */
1485                         offset = strascent(paren_string) -
1486                                         (strheight(paren_string) / 2.0);
1487
1488                         /* print the '(', the accidental, and the ')' */
1489                         pr_string(grpsyl_p->c[AX] + noteinfo_p->waccr,
1490                                         noteinfo_p->c[AY] - offset,
1491                                         paren_string, J_LEFT,
1492                                         grpsyl_p->inputfile,
1493                                         grpsyl_p->inputlineno);
1494
1495                         pr_muschar(_Cur[AX] +
1496                                         width(FONT_MUSIC, a_size, muschar) / 2.0,
1497                                         noteinfo_p->c[AY], muschar, size,
1498                                         FONT_MUSIC);
1499
1500                         (void) sprintf(paren_string, "%c%c%c",
1501                                                         FONT_TR, a_size, ')');
1502                         pr_string(_Cur[AX], noteinfo_p->c[AY] - offset,
1503                                         paren_string, J_LEFT,
1504                                         grpsyl_p->inputfile,
1505                                         grpsyl_p->inputlineno);
1506                 }
1507         }
1508 }
1509 \f
1510
1511 /* print appropriate number of leger lines */
1512
1513 static void
1514 pr_leger(noteinfo_p, gs_p, staffno)
1515
1516 struct NOTE *noteinfo_p;        /* info about current note */
1517 struct GRPSYL *gs_p;            /* which group contains the note */
1518 int staffno;                    /* which staff to draw relative to */
1519
1520 {
1521         register int lines2draw;        /* how many leger lines are needed */
1522         float sign;                     /* 1 for above or -1 for below staff */
1523         float y;                        /* vertical position */
1524         float left_leger, right_leger;  /* how far legers stick out from note */
1525         int is_intermediate;            /* YES if inner, NO if outermost */
1526         int on_other_side;              /* YES if on "wrong" side of stem */
1527
1528
1529         if ((lines2draw = numlegers(noteinfo_p)) < 1) {
1530                 /* No legers needed for this note */
1531                 return;
1532         }
1533
1534         /* Is note above or below the middle of the staff? */
1535         sign = noteinfo_p->stepsup > 0.0 ? 1.0 : -1.0;
1536
1537         /* For notes on the "wrong" side of the stem, we will only need
1538          * to draw the outermost leger. */
1539         if ( (gs_p->stemdir == DOWN && noteinfo_p->c[AE] < gs_p->c[AX]) ||
1540                         (gs_p->stemdir == UP && noteinfo_p->c[AW] > gs_p->c[AX])) {
1541                 on_other_side = YES;
1542         }
1543         else {
1544                 on_other_side = NO;
1545         }
1546
1547         /* Draw the legers */
1548         do_linetype(L_NORMAL);
1549         is_intermediate = NO;
1550         for (    ; lines2draw > 0; lines2draw--) {
1551
1552                 /* Find the y location for the leger line.
1553                  * They are 2 Stepsizes apart,
1554                  * beginning at the edge of the staff  */
1555                 y = Staffs_y[staffno]
1556                                 + (sign * (2 + lines2draw) * (2 * Stepsize));
1557
1558                 /* If things are packed really close together, leger lines
1559                  * could bleed into leger lines of the neighboring chord.
1560                  * We need to see if there are any potentially
1561                  * troublesome leger lines on either side, and shorten
1562                  * this leger if necessary to avoid them.
1563                  */
1564                 left_leger = leger_length(noteinfo_p, gs_p->prev, lines2draw,
1565                                 YES, is_intermediate);
1566                 right_leger = leger_length(noteinfo_p, gs_p->next, lines2draw,
1567                                 NO, is_intermediate);
1568
1569                 draw_line( noteinfo_p->c[AW] - left_leger, y,
1570                         noteinfo_p->c[AE] + right_leger, y);
1571                 is_intermediate = YES;
1572
1573                 /* For notes on the "wrong" side of the stem, we only need
1574                  * to draw the outermost leger */
1575                 if (on_other_side == YES) {
1576                         break;
1577                 }
1578         }
1579 }
1580 \f
1581
1582 /* How many legers to draw is absolute value of stepsup divided
1583  * by 2 minus the 2 lines that are already in the staff.
1584  * Note that we only do legers on normal 5-line staffs. */
1585
1586 static int
1587 numlegers(noteinfo_p)
1588
1589 struct NOTE *noteinfo_p;
1590
1591 {
1592         return (abs(noteinfo_p->stepsup) / 2) - 2;
1593 }
1594 \f
1595
1596 /* If things are packed really close together, leger lines
1597  * could bleed into leger lines of the neighboring chord.
1598  * This function will detect that and shorten them if necessary.
1599  * To be completely correct, it should check all the voices on the
1600  * staff, but that would be quite a bit more work, and chances of colliding
1601  * with another voice's notes is not very high, so we just check
1602  * the voice of the note in question.
1603  */
1604
1605 static double
1606 leger_length(noteinfo_p, othergs_p, lines, other_is_prev, is_intermediate)
1607
1608 struct NOTE *noteinfo_p;        /* we are finding leger length for this note */
1609 struct GRPSYL *othergs_p;       /* check this group for a too close note */
1610 int lines;                      /* how many leger lines to draw */
1611 int other_is_prev;              /* YES if othergs_p is ->prev, NO if ->next */
1612 int is_intermediate;            /* YES if interior, NO is outermost leger */
1613
1614 {
1615         int n;                          /* note index */
1616         double distance;                /* between 2 notes */
1617         double length = 2.2 * Stdpad;   /* length of leger. Init to default */
1618         double adjust;                  /* inners can be shortened extra */
1619
1620
1621         if (othergs_p == 0) {
1622                 /* No group to collide with */
1623                 return(length);
1624         }
1625         if (othergs_p->grpcont != GC_NOTES) {
1626                 /* Can't have leger lines */
1627                 return(length);
1628         }
1629
1630         /* Legers that are not through or right next to the note
1631          * can be shortened a bit more to make their gap show up better.
1632          */
1633         adjust = (is_intermediate ? 0.5 * Stdpad : 0.0);
1634
1635         /* See if othergs_p has any notes that are too close */
1636         for (n = 0; n < othergs_p->nnotes; n++) {
1637                 if (numlegers( &(othergs_p->notelist[n]) ) < lines) {
1638                         /* Neighboring note has fewer legers; not relevant */
1639                         continue;
1640                 }
1641                 if (noteinfo_p->stepsup > 0 &&
1642                                         othergs_p->notelist[n].stepsup < 0) {
1643                         /* Neighboring note's legers are below, ours above.
1644                          * The remaining neighboring notes are irrelevant. */
1645                         break;
1646                 }
1647                 if (noteinfo_p->stepsup < 0 &&
1648                                         othergs_p->notelist[n].stepsup > 0) {
1649                         /* Neighboring note's legers are above, ours below.
1650                          * Haven't gotten to any potentially relevant
1651                          * notes yet. */
1652                         continue;
1653                 }
1654
1655                 /* We have a pair of notes whose leger lines might collide.
1656                  * See how far apart they are. */
1657                 if (other_is_prev == YES) {
1658                         distance = noteinfo_p->c[AW] - othergs_p->notelist[n].c[AE];
1659                 }
1660                 else {
1661                         distance = othergs_p->notelist[n].c[AW] - noteinfo_p->c[AE];
1662                 }
1663
1664                 /* Ideally, we try to make leger lines 2.2 Stdpads on each side,
1665                  * but if that leaves less than 2.0 Stdpads between them,
1666                  * we shorten them until they get down to 0.7 Stdpads.
1667                  * After that we let them join. That should only happen
1668                  * if things are really tightly packed.
1669                  * The 6.4 is from two legers of 2.2 each with 2.0 between.
1670                  */
1671                 if (distance < 6.4 * Stdpad) {
1672                         /* Too close. Will have to shorten */
1673                         length = (distance - (2.0 * Stdpad)) / 2.0 - adjust;
1674                         if (length < 0.7 * Stdpad - adjust) {
1675                                 /* No shorter than minimum */
1676                                 length = 0.7 * Stdpad - adjust;
1677                         }
1678                 }
1679         }
1680         return (length);
1681 }
1682 \f
1683
1684 /* given the first group of a tuplet, return, via pointers, the x coords of
1685  * the left and right boundaries of the tuplet number and its height.
1686  * Return pointer to static string containing the tuplet number itself in
1687  * internal string format */
1688
1689 char *
1690 tupnumsize(gs_p, west_p, east_p, height_p, staff_p)
1691
1692 struct GRPSYL *gs_p;
1693 float *west_p;          /* west coord returned here */
1694 float *east_p;          /* east coord returned here */
1695 float *height_p;        /* string height returned here */
1696 struct STAFF *staff_p;  /* staff pointing at gs_p */
1697
1698 {
1699         char *numstr;                   /* tuplet number as internal string */
1700         struct GRPSYL *last_gs_p;       /* last group in tuplet */
1701         float num_x;                    /* x coord of number */
1702         float halfnumwidth;             /* half the width of numstr */
1703         int tupside;
1704         int all_cue;
1705
1706
1707         /* assume all cue till proven otherwise */
1708         all_cue = YES;
1709
1710         /* find x of middle of tuplet number */
1711         if (gs_p->tuploc == LONEITEM) {
1712                 if (gs_p->grpsize != GS_SMALL) {
1713                         all_cue = NO;
1714                 }
1715                 num_x = gs_p->c[AX];
1716         }
1717         else {
1718                 for (last_gs_p = gs_p->next; last_gs_p != (struct GRPSYL *) 0;
1719                                         last_gs_p = last_gs_p->next) {
1720                         if (gs_p->grpsize != GS_SMALL) {
1721                                 all_cue = NO;
1722                         }
1723                         if (last_gs_p->tuploc == ENDITEM) {
1724                                 break;
1725                         }
1726                 }
1727                 if (last_gs_p == (struct GRPSYL *) 0) {
1728                         pfatal("missing end tuplet in tupnumsize");
1729                 }
1730
1731                 /* Usually, the x location of tuplet number is average of
1732                  * beginning and end group x coords. But if there is a beam
1733                  * and the number is being printed on the beam side,
1734                  * and there is no bracket being printed,
1735                  * it generally looks better to center between the stems.
1736                  */
1737                 tupside = tupdir(gs_p, staff_p);
1738                 if (gs_p->beamloc == STARTITEM && last_gs_p->beamloc == ENDITEM
1739                                 && ((tupside == PL_ABOVE && gs_p->stemdir == UP)
1740                                 || (tupside == PL_BELOW && gs_p->stemdir == DOWN))
1741                                 && tupgetsbrack(gs_p) == NO) {
1742                         num_x = (find_x_stem(last_gs_p) + find_x_stem(gs_p)) / 2.0;
1743                 }
1744                 else {
1745                         num_x = (last_gs_p->c[AX]  + gs_p->c[AX]) / 2.0;
1746                 }
1747         }
1748
1749         /* prepare the string to print */
1750         numstr = num2str(gs_p->tupcont);
1751         /* force to 11-point newcentury bold-italics, unless all cue,
1752          * then smaller */
1753         numstr[0] = FONT_NX;
1754         numstr[1] = (char) adj_size((all_cue == YES ? 9 : 11), Staffscale,
1755                                 (char *) 0, -1);
1756         halfnumwidth = strwidth(numstr) / 2.0;
1757
1758         /* return the values */
1759         *west_p =  num_x - halfnumwidth - Stdpad;
1760         *east_p = num_x + halfnumwidth + Stdpad;
1761         *height_p = strheight(numstr);
1762         return(numstr);
1763 }
1764 \f
1765
1766 /* go through measure. If there are any tuplets, print a number by them,
1767  * along with bracket if appropriate. */
1768
1769 static void
1770 pr_tupnums(gs_p, staff_p)
1771
1772 struct GRPSYL *gs_p;    /* start from here to walk through list of groups */
1773 struct STAFF *staff_p;  /* staff pointing to gs_p */
1774
1775 {
1776         struct GRPSYL *first_gs_p = 0;  /* where to begin tuplet label.
1777                                  * Initialization is just to shut up bogus
1778                                  * compiler warning. */
1779         struct GRPSYL *g_p;     /* to check for all spaces */
1780         float x1, x2;           /* where tuplet bracket begins & ends */
1781         float num_y;            /* y of tuplet number */
1782         float y1, y2;           /* y coord of ends of bracket */
1783         char *numstr;           /* ASCII version of tuplet number */
1784         float numeast, numwest; /* boundaries of tuplet number */
1785         float height;           /* of tuplet number */
1786         float y_adjust;         /* adjustment for space taken by number */
1787         float x_adjust;         /* from group x to where bracket goes */
1788         int num_notes = 0;      /* how many notes in tuplet */
1789         int need_brack = NO;    /* set to YES if the beaming of the notes
1790                                  * doesn't match the tuplet boundaries */
1791         float brackdir;         /* how far in y direction to draw bracket ends
1792                                  * (positive or negative depending on the
1793                                  * direction that the bracket points) */
1794         int size;
1795
1796
1797         /* go through all the groups */
1798         for (   ; gs_p != (struct GRPSYL *) 0; gs_p = gs_p->next) {
1799
1800                 switch (gs_p->tuploc) {
1801
1802                 case NOITEM:
1803                         break;
1804
1805                 case STARTITEM:
1806                         /* remember beginning for later use */
1807                         first_gs_p = gs_p;
1808                         num_notes = 1;
1809                         break;
1810
1811                 case INITEM:
1812                         num_notes++;
1813                         break;
1814
1815                 case LONEITEM:
1816                         first_gs_p = gs_p;
1817                         /*FALLTHRU*/
1818
1819                 case ENDITEM:
1820                         num_notes++;
1821                         
1822                         /* if not to be printed, nothing to do except reinit */
1823                         if (gs_p->printtup == PT_NEITHER) {
1824                                 num_notes = 0;
1825                                 break;
1826                         }
1827
1828                         /* we don't do tuplet numbers on cross-staff beams--
1829                          * it's virtually impossible to know where to put them
1830                          */
1831                         if (gs_p->beamto != CS_SAME) {
1832                                 num_notes = 0;
1833                                 break;
1834                         }
1835
1836                         /* If the tuplet is all spaces,
1837                          * there is nothing to draw a bracket over,
1838                          * and trying to do so causes problems,
1839                          * so don't try. */
1840                         for (g_p = first_gs_p; g_p->tuploc != NOITEM;
1841                                                         g_p = g_p->next) {
1842                                 if (g_p->grpcont != GC_SPACE) {
1843                                         /* good--it has something
1844                                          * other than spaces */
1845                                         break;
1846                                 }
1847
1848                                 if (g_p->tuploc == ENDITEM
1849                                                 || g_p->tuploc == LONEITEM) {
1850                                         /* reached end of all-space tuplet */
1851                                         break;
1852                                 }
1853                         }
1854                         if (g_p->grpcont == GC_SPACE) {
1855                                 /* must have been all spaces */
1856                                 num_notes = 0;
1857                                 break;
1858                         }
1859
1860                         /* if tuplet doesn't match beaming, need bracket */
1861                         need_brack = tupgetsbrack(first_gs_p);
1862
1863                         if (num_notes == 0) {
1864                                 pfatal("no notes in tuplet");
1865                         }
1866
1867                         numstr = tupnumsize(first_gs_p, &numwest, &numeast,
1868                                                         &height, staff_p);
1869
1870                         if (tupdir(first_gs_p, staff_p) == PL_ABOVE) {
1871                                 y_adjust = strascent(numstr);
1872                                 y1 = first_gs_p->c[AN] - y_adjust;
1873                                 y2 = gs_p->c[AN] - y_adjust;
1874                                 brackdir = -3.0 * Stdpad;
1875                         }
1876                         else {
1877                                 /* print below */
1878                                 y1 = first_gs_p->c[AS];
1879                                 y2 = gs_p->c[AS];
1880                                 brackdir = 3.0 * Stdpad;
1881                         }
1882
1883                         /* print tuplet number at correct place */
1884                         y1 += first_gs_p->tupextend;
1885                         y2 += gs_p->tupextend;
1886                         num_y = (y1 + y2) / 2.0;
1887                         pr_string(numwest + Stdpad, num_y, numstr, J_LEFT,
1888                                         gs_p->inputfile, gs_p->inputlineno);
1889
1890                         /* add tuplet bracket if necessary */
1891                         if (need_brack == YES) {
1892                                 do_linetype(L_NORMAL);
1893                                 
1894                                 /* adjust to reach edge of note head */
1895                                 size = (first_gs_p->grpsize == GS_NORMAL ?
1896                                                 DFLT_SIZE : SMALLSIZE)
1897                                                 * Staffscale;
1898                                 if (first_gs_p->grpcont == GC_NOTES) {
1899                                         x_adjust = widest_head(first_gs_p)
1900                                                 * Staffscale / 2.0;
1901                                 }
1902                                 else if (first_gs_p->grpcont == GC_REST) {
1903                                         x_adjust = width(FONT_MUSIC, size,
1904
1905                                                 restchar(first_gs_p->basictime))
1906                                                 / 2.0;
1907                                 }
1908                                 else {
1909                                         x_adjust = 0.0;
1910                                 }
1911                                 x1 = first_gs_p->c[AX] - x_adjust;
1912
1913                                 size = (gs_p->grpsize == GS_NORMAL ?
1914                                                 DFLT_SIZE : SMALLSIZE)
1915                                                 * Staffscale;
1916                                 if (gs_p->grpcont == GC_NOTES) {
1917                                         x_adjust = widest_head(gs_p)
1918                                                 * Staffscale / 2.0;
1919                                 }
1920                                 else if (gs_p->grpcont == GC_REST) {
1921                                         x_adjust = width(FONT_MUSIC, size,
1922                                                 restchar(gs_p->basictime))
1923                                                 / 2.0;
1924                                 }
1925                                 else {
1926                                         x_adjust = 0.0;
1927                                 }
1928                                 x2 = gs_p->c[AX] + x_adjust;
1929
1930                                 /* move the bracket line up from the baseline
1931                                  * of the number */
1932                                 y1 += (4.0 * Stdpad);
1933                                 y2 += (4.0 * Stdpad);
1934                                 num_y += (4.0 * Stdpad);
1935
1936                                 /* figure out how much to adjust y from num_y
1937                                  * to account for the space taken up by the
1938                                  * number. Use ratio of similar triangles. */
1939                                 if (numwest - x1 == 0.0) {
1940                                         /* avoid any chance of divide by 0 */
1941                                         y_adjust = 0.0;
1942                                 }
1943                                 else {
1944                                         y_adjust = (((numeast - numwest
1945                                                 + (Stdpad * 2.0)) *
1946                                                 (num_y - y1)) / (numeast - x1))
1947                                                 / 2.0;
1948                                 }
1949
1950                                 draw_line(x1, y1, numwest - Stdpad,
1951                                                 num_y - y_adjust); 
1952                                 draw_line(numeast + Stdpad,
1953                                                 num_y + y_adjust, x2, y2); 
1954                                 draw_line(x1, y1, x1, y1 + brackdir);
1955                                 draw_line(x2, y2, x2, y2 + brackdir); 
1956                         }
1957
1958                         /* re-init in case other tuplets in same measure */
1959                         num_notes = 0;
1960
1961                         break;
1962
1963                 default:
1964                         pfatal("bad tuplet type");
1965                         break;
1966                 }
1967         }
1968 }
1969 \f
1970
1971 /* utility function. Given the first group in a tuplet, return YES if it
1972  * is to have a bracket printed. It does if the tuplet itself is to be printed,
1973  * and if not a LONEITEM and if any of the beamlocs do not match the tuploc */
1974
1975 int
1976 tupgetsbrack(gs_p)
1977
1978 struct GRPSYL *gs_p;    /* first group of tuplet */
1979
1980 {
1981         /* If nothing is to be printed or number only, no bracket */
1982         if (gs_p->printtup == PT_NEITHER || gs_p->printtup == PT_NUMBER) {
1983                 return(NO);
1984         }
1985
1986         /* single chord tuplets never get a bracket -- not enough room
1987          * to draw one */
1988         if (gs_p->tuploc == LONEITEM) {
1989                 return(NO);
1990         }
1991
1992         /* if user insists on a bracket, we oblige */
1993         if (gs_p->printtup == PT_BOTH) {
1994                 return(YES);
1995         }
1996
1997         /* check for mismatches between beamloc and tuploc. */
1998         for (  ; gs_p != (struct GRPSYL *) 0; gs_p = gs_p->next) {
1999                 /* grace notes don't count */
2000                 if (gs_p->grpvalue == GV_ZERO) {
2001                         continue;
2002                 }
2003
2004                 if (gs_p->tuploc != gs_p->beamloc) {
2005                         return(YES);
2006                 }
2007                 if (gs_p->tuploc == ENDITEM) {
2008                         /* matched beam everywhere, so no bracket needed */
2009                         return(NO);
2010                 }
2011         }
2012         pfatal("missing end tuplet");
2013
2014         /*NOTREACHED*/
2015         return(NO);
2016 }
2017 \f
2018
2019 /* utility function to return PL_ABOVE  or PL_BELOW
2020  * depending on whether the number for
2021  * the given tuplet should get printed above or below the groups */
2022 /* Can be passed any group in the tuplet. If not the first, it will find the
2023  * first and go from there */
2024
2025 int
2026 tupdir(gs_p, staff_p)
2027
2028 struct GRPSYL *gs_p;    /* group in tuplet */
2029 struct STAFF *staff_p;  /* staff pointing to gs_p */
2030
2031 {
2032         RATIONAL starttime, endtime;    /* begin & end time of tuplet */
2033         struct GRPSYL *save_gs_p;       /* temporarily save value of gs_p */
2034         int othervoice;                 /* array subscript in staff_p->groups_p
2035                                          * of the other voice on this staff */
2036         int vscheme;                    /* V_* value */
2037         RATIONAL smalltime;
2038
2039
2040         smalltime.n = 1;
2041         smalltime.d = 2 * MAXBASICTIME;
2042
2043
2044         switch (gs_p->tuploc) {
2045
2046         case LONEITEM:
2047         case STARTITEM:
2048                 /* this is the one we want */
2049                 break;
2050
2051         case NOITEM:
2052                 pfatal("arg of tupdir is not in a tuplet");
2053                 /*NOTREACHED*/
2054                 break;
2055         default:
2056                 /* have to back up to beginning of tuplet first */
2057                 for (    ; gs_p != (struct GRPSYL *) 0; gs_p = gs_p->prev) {
2058                         if (gs_p->tuploc == STARTITEM) {
2059                                 break;
2060                         }
2061                 }
2062                 if (gs_p == (struct GRPSYL *) 0) {
2063                         pfatal("can't find beginning of tuplet");
2064                 }
2065                 break;
2066         }
2067
2068         /* figure out which side. First determine vscheme */
2069
2070         /* there is a circumstance where we're looking at an entire score,
2071          * (in relvert), and if some of the score has V_1 and some of it
2072          * doesn't, it's possible for us to get confused and think something
2073          * isn't V_1 when it is. We would then try to look at the other
2074          * voice, which is null, and would blow up. To avoid this, if one
2075          * voice is null, treat measure as V_1 regardless of what vscheme
2076          * might lead us to believe.
2077          */
2078         if (staff_p->groups_p[1] == (struct GRPSYL *) 0) {
2079                 return(tupdir1voice(gs_p));
2080         }
2081
2082         /* voice 3 pays no attention to any other voices. */
2083         if (gs_p->vno == 3) {
2084                 return(tupdir1voice(gs_p));
2085         }
2086
2087         if ((vscheme = svpath(staff_p->staffno, VSCHEME)->vscheme) == V_1) {
2088                 return(tupdir1voice(gs_p));
2089         }
2090         else if (vscheme == V_2OPSTEM) {
2091                 /* 2 opposing stem voices, always put tuplet above voice 1 and
2092                  * below voice 2 */
2093                 if (gs_p->tupside != PL_UNKNOWN) {
2094                         l_warning(gs_p->inputfile, gs_p->inputlineno,
2095                                         "tuplet side specification not valid when vscheme=2o");
2096                         /* fix so we don't print error again if called
2097                          * again on this tuplet */
2098                         gs_p->tupside = PL_UNKNOWN;
2099                 }
2100                 return(gs_p->vno == 1 ? PL_ABOVE : PL_BELOW);
2101         }
2102         else {
2103                 /* find the time period taken by tuplet */
2104                 save_gs_p = gs_p;
2105                 starttime = Zero;
2106                 /* find time to where tuplet begins */
2107                 for (gs_p = gs_p->prev; gs_p != (struct GRPSYL *) 0;
2108                                                         gs_p = gs_p->prev) {
2109                         starttime = radd(starttime, gs_p->fulltime);
2110                 }
2111                 /* find time up to last note of tuplet */
2112                 endtime = starttime;
2113                 for (gs_p = save_gs_p; gs_p->tuploc != ENDITEM
2114                                         && gs_p->tuploc != LONEITEM;
2115                                         gs_p = gs_p->next) {
2116                         endtime = radd(endtime, gs_p->fulltime);
2117                 }
2118                 /* add on a little bit for the final group of the tuplet */
2119                 endtime = radd(endtime, smalltime);
2120
2121                 /* now check if other voice has space or not */
2122                 othervoice = (gs_p->vno == 1 ? 1 : 0);
2123                 if (hasspace(staff_p->groups_p [othervoice], starttime, endtime)
2124                                                 == YES) {
2125                         /* other voice is space: treat like V_1 */
2126                         return(tupdir1voice(save_gs_p));
2127                 }
2128                 else {
2129                         /* other voice not space: treat like V_2OPSTEM */
2130                         if (gs_p->tupside != PL_UNKNOWN) {
2131                                 l_warning(gs_p->inputfile, gs_p->inputlineno,
2132                                         "tuplet side specification not valid when there are two voices");
2133                                 /* fix so we don't print error again if called
2134                                  * again on this tuplet */
2135                                 gs_p->tupside = PL_UNKNOWN;
2136                         }
2137                         return(gs_p->vno == 1 ? PL_ABOVE : PL_BELOW);
2138                 }
2139         }
2140 }
2141 \f
2142
2143 /* return PL_ABOVE or PL_BELOW for tup location assuming a single voice */
2144
2145 static int
2146 tupdir1voice(gs_p)
2147
2148 struct GRPSYL *gs_p;    /* first group of tuplet */
2149
2150 {
2151         int stemdirsum; /* sum of stem directions to see if mostly up or down */
2152
2153
2154         /* if user specified a direction, the answer is easy */
2155         if (gs_p->tupside != PL_UNKNOWN) {
2156                 return(gs_p->tupside);
2157         }
2158
2159         /* Count up stem directions. Whichever side
2160          * has more stems, put it on that side. In case of tie,
2161          * arbitrarily choose above. */
2162         stemdirsum = 0;
2163         for (   ; gs_p != (struct GRPSYL *) 0; gs_p = gs_p->next) {
2164                 if (gs_p->grpcont == GC_NOTES && gs_p->grpvalue != GV_ZERO) {
2165                         stemdirsum += (gs_p->stemdir == UP ? 1 : -1);
2166                 }
2167                 if (gs_p->tuploc == LONEITEM || gs_p->tuploc == ENDITEM) {
2168                         break;
2169                 }
2170         }
2171
2172         return(stemdirsum >= 0 ? PL_ABOVE : PL_BELOW);
2173 }
2174 \f
2175
2176 /* go through measure, printing any beams. Gets called once for normal sized
2177  * notes, once for cue notes, and once for grace note. */
2178
2179 static void
2180 pr_beams(gs_p, grpvalue, grpsize)
2181
2182 struct GRPSYL *gs_p;    /* list of grpsyls for current measure
2183                          * of current voice */
2184 int grpvalue;           /* GV_NORMAL, GV_ZERO */
2185 int grpsize;            /* GS_NORMAL, GS_SMALL */
2186
2187 {
2188         struct GRPSYL *startbeam_p;     /* first in beam group */
2189         int t;                          /* 8, 16, etc for basictimes */
2190
2191
2192         /* go through all the grpsyls in measure */
2193         for (   ; gs_p != (struct GRPSYL *) 0; gs_p = gs_p->next) {
2194
2195                 /* skip until we find a STARTITEM
2196                  * on the relevant kind of group */
2197                 if (gs_p->beamloc != STARTITEM || gs_p->grpvalue != grpvalue
2198                                         || gs_p->grpsize != grpsize) {
2199                         continue;
2200                 }
2201
2202                 /* when there are cross-staff beams, we will find the beam
2203                  * on both staffs, but only need to draw it once. So skip
2204                  * it the second time */
2205                 if (gs_p->beamto == CS_ABOVE) {
2206                         continue;
2207                 }
2208
2209                 /* find the matching ENDITEM */
2210                 for (startbeam_p = gs_p; gs_p != 0 && (gs_p->beamloc != ENDITEM
2211                                         || gs_p->grpvalue != grpvalue
2212                                         || gs_p->grpsize != grpsize);
2213                                         gs_p = gs_p->next) {
2214
2215                 }
2216                 if (gs_p == 0) {
2217                         pfatal("pr_beams couldn't find end of beam group");
2218                 }
2219
2220                 /* now go through beam group drawing beams for 8th notes,
2221                  * then 16th, etc */
2222                 for (t = 8; t <= MAXBASICTIME; t <<= 1) {
2223                         if (draw_beams(startbeam_p, gs_p, t, grpsize, grpvalue)
2224                                                                 <= 0) {
2225                                 break;
2226                         }
2227                 }
2228         }
2229 }
2230 \f
2231
2232 /* In the case of cross-staff beams with the above staff's stems down,
2233  * and the below staff's stems up, we need to do extra work.
2234  * This function builds up a mesh of structs that represent the beams,
2235  * with a row of CSBINFO structs linked horizontally for each beam,
2236  * and vertical links at each stem. end_bm_offset() then uses this information
2237  * to figure out where along the stem a beam ends.
2238  * This function returns a pointer to the beginning of the 8th note beam.
2239  *
2240  * As an example, consider this input:
2241  *   1: 8.c; 64f beam with staff below; 32.s; 16e; 8s; 8e; 16s; 32.f; 64s ebm;
2242  *   2: 8.e; 64s beam with staff above; 32.a; 16s; 8g; 8s; 16g; 32.s; 64a ebm;
2243  * The resulting mesh will look like this:
2244  *                    .           .           .           .
2245  *                    .           .           .           .
2246  *       (64th)       X           .           .           .
2247  *                    |           .           .           .
2248  *       (32nd)       X --> X     .           .           .
2249  *                    |     |     .           .           .
2250  *       (16th)       X --> X --> X           .           X --> X   (32nd)
2251  *                    |     |     |           .           |     |
2252  *   return_value --> X --> X --> X --> X --> X --> X --> X --> X   (8th)
2253  *                          .           .           |     |     |
2254  *                          .           .           X --> X --> X   (16th)
2255  *                          .           .           .           |
2256  *                          .           .           .           X   (64th)
2257  *                          .           .           .           .
2258  *                          .           .           .           .
2259  *
2260  * Each X in the diagram represents a CSBINFO struct.
2261  * Each row represents a beam. The --> is the "next" field.
2262  * Each column represents a stem. It is a doubly-linked list,
2263  * using above_p and below_p fields.
2264  * The dots show the stem direction.
2265  */
2266
2267 static struct CSBINFO *
2268 mkcsbmesh(begin_p, end_p)
2269
2270 struct GRPSYL *begin_p; /* first group of cross-staff beam on upper staff */
2271 struct GRPSYL *end_p;   /* 8th note beam goes from begin_p to end_p.
2272                          * There may be zero or more additional beams
2273                          * for shorter durations that span part or all
2274                          * of this list.
2275                          */
2276
2277 {
2278         struct CSBINFO *csbi_list_p;    /* this points to the 8th note beam
2279                                          * list, which is what will
2280                                          * ultimately be returned */
2281         struct CSBINFO *csbi_p;         /* the current information */
2282         struct CSBINFO *csbi8_p;        /* to walk through 8th list */
2283         struct CSBINFO *prevcsbi_p;     /* previous in horizontal list */
2284         struct CSBINFO *c_p;            /* for walking vertical lists */
2285         struct GRPSYL *gs_p;            /* to walk through beamed groups */
2286         int basictime;                  /* 8, 16, 32, etc */
2287         int stemdir;                    /* stem direction where beam starts */
2288         int shortest;                   /* shortest basictime (8, 16, ...) */
2289
2290
2291         /* There is always at least an 8th note beam that goes the
2292          * entire length, so make a list for that. */
2293         csbi_list_p = prevcsbi_p = 0;
2294         shortest = 8;
2295         for (gs_p = begin_p; gs_p != end_p->next; gs_p = nxtbmgrp(gs_p,
2296                                                 begin_p, end_p->next)) {
2297                 MALLOC(CSBINFO, csbi_p, 1);
2298
2299                 /* set horizontal list links */
2300                 if (csbi_list_p == 0) {
2301                         /* first item on the horizontal list */
2302                         csbi_list_p = csbi_p;
2303                 }
2304                 else {
2305                         /* link from previous horizontally */
2306                         prevcsbi_p->next = csbi_p;
2307                 }
2308                 prevcsbi_p = csbi_p;
2309                 csbi_p->next = 0;
2310
2311                 /* init vertical list links */
2312                 csbi_p->above_p = csbi_p->below_p = 0;
2313
2314                 /* this is for the 8th note beam */
2315                 csbi_p->basictime = 8;
2316                 /* save what group this is for, for later convenience */
2317                 csbi_p->gs_p = gs_p;
2318
2319                 /* remember the shortest basictime anywhere in the beam */
2320                 if (gs_p->basictime > shortest) {
2321                         shortest = gs_p->basictime;
2322                 }
2323         }
2324
2325         /* For each additional beam, build up a row of structs representing
2326          * that beam, and link it vertically to the row below or above it,
2327          * depending on whether the first group of the beam is on the staff
2328          * above or below the 8th beam.
2329          */
2330         for (basictime = 16; basictime <= shortest; basictime <<= 1) {
2331                 stemdir = UNKNOWN;      /* Init to keep lint happy;
2332                                          * this will get set to appropriate
2333                                          * value before it is actually used. */
2334                 prevcsbi_p = 0;         /* No run of groups found yet */
2335
2336                 /* Walk through list, finding any runs of groups that are
2337                  * at least as short in duration as the current basictime
2338                  * we are looking for. Note this could be as little as a single
2339                  * group in the case of a partial beam.
2340                  * We walk through the GRPSYLs and their
2341                  * corresponding CSBINFO structs in parallel.
2342                  */
2343                 for (gs_p = begin_p, csbi8_p = csbi_list_p;
2344                                 gs_p != end_p->next;
2345                                 gs_p = nxtbmgrp(gs_p, begin_p, end_p->next),
2346                                 csbi8_p = csbi8_p->next) {
2347
2348                         if (gs_p->basictime >= basictime) {
2349                                 /* this group is part of a beam of at least
2350                                  * as short as the basictime of interest. */
2351                                 MALLOC(CSBINFO, csbi_p, 1);
2352                                 csbi_p->next = 0;
2353                                 csbi_p->basictime = basictime;
2354
2355                                 /* If not first group in this beam,
2356                                  * link from previous. If is first,
2357                                  * save its stem direction. That determines
2358                                  * which side of the 8th beam it goes on. */
2359                                 if (prevcsbi_p != 0) {
2360                                         prevcsbi_p->next = csbi_p;
2361                                 }
2362                                 else {
2363                                         stemdir = gs_p->stemdir;
2364                                 }
2365                                 /* Prepare to link more on horizonally,
2366                                  * if beam goes further. */
2367                                 prevcsbi_p = csbi_p;
2368
2369                                 /* set vertical links */
2370                                 if (stemdir == DOWN) {
2371                                         /* Must be from staff above.
2372                                          * Find current top, and add
2373                                          * above there */
2374                                         for (c_p = csbi8_p; c_p->above_p != 0;
2375                                                         c_p = c_p->above_p) {
2376                                                 ;
2377                                         }
2378                                         c_p->above_p = csbi_p;
2379                                         csbi_p->below_p = c_p;
2380                                         csbi_p->above_p = 0;
2381                                 }
2382                                 else {
2383                                         /* similar for from staff below */
2384                                         for (c_p = csbi8_p; c_p->below_p != 0;
2385                                                         c_p = c_p->below_p) {
2386                                                 ;
2387                                         }
2388                                         c_p->below_p = csbi_p;
2389                                         csbi_p->above_p = c_p;
2390                                         csbi_p->below_p = 0;
2391                                 }
2392                         }
2393                         else {
2394                                 /* If we were doing a beam before,
2395                                  * it's done now */
2396                                 prevcsbi_p = 0;
2397                         }
2398                 }
2399         }
2400         return(csbi_list_p);
2401 }
2402 \f
2403
2404 /* draw beams in a beam group for a particular time value, 8th, 16th, etc */
2405 /* this gets called repeatedly, first for 8th, then 16ths, etc, until
2406  * there are no more shorter notes.
2407  * It returns the number of beams drawn (including partials) */
2408
2409
2410 static int
2411 draw_beams(gs_p, endbeam_p, basictime, grpsize, grpvalue)
2412
2413 struct GRPSYL *gs_p;                    /* start of beam group */
2414 struct GRPSYL *endbeam_p;               /* end of beam group */
2415 int basictime;                          /* draw beam for this basic time:
2416                                          * 8, 16, 32, 64, etc */
2417 int grpsize;                            /* GS_NORMAL, GS_SMALL */
2418 int grpvalue;                           /* GV_NORMAL, GV_ZERO */
2419
2420 {
2421         int found = 0;          /* how many beams found to be drawn */
2422         int ngrps;              /* how many groups to beam together */
2423         struct GRPSYL *first_p = 0;/* first group in beam (the one on the
2424                                  * above staff while doing cross-staff beams) */
2425         struct GRPSYL *begin_p = 0, *end_p;     /* the initialization is
2426                                  * to shut up bogus compiler warning */
2427         struct GRPSYL *other_p; /* other note that must be used to calculate
2428                                  * slope of partial beam */
2429         float y_offset;         /* from end of stem to draw beam */
2430         int side;               /* left or right for partial beam */
2431         float x_begin, y_begin, x_other, y_other;       /* partial beam
2432                                                          * coordinates */
2433         double halfwidth;       /* half width of a beam */
2434         double end_y_offset;    /* to deal with cross staff beams */
2435         double slope;           /* of partial beam */
2436         double halfstem;
2437         double stemdist;        /* distance between stems */
2438         double pbeam_len;       /* length of partial beam */
2439
2440
2441         /* get relevant group, accounting for cross-staff beams */
2442         first_p = gs_p;
2443         gs_p = neighboring_note_beam_group(gs_p, first_p, NO);
2444
2445         /* go through the list */
2446         while ( gs_p != endbeam_p->next) {
2447
2448                 /* find however many in a row deserve to get another beam */
2449                 for (end_p = (struct GRPSYL *) 0, ngrps = 0;
2450                                                 (gs_p != endbeam_p->next);
2451                                                 gs_p = nxtbmgrp(gs_p,
2452                                                 first_p, endbeam_p->next)) {
2453
2454                         /* if wrong type (e.g a grace inside of
2455                          * a set of normal notes), skip over */
2456                         if (gs_p->grpsize != grpsize
2457                                         || gs_p->grpvalue != grpvalue ) {
2458                                 continue;
2459                         }
2460
2461                         /* if not beamed, skip */
2462                         if ( gs_p->beamloc == NOITEM) {
2463                                 pfatal("non-beam inside beam group\n");
2464                         }
2465
2466                         /* if this one deserves another beam,
2467                          * keep track of that. If not, break out */
2468                         if (gs_p->basictime >= basictime) {
2469                                 end_p = gs_p;
2470                                 found++;
2471                                 if (ngrps == 0) {
2472                                         begin_p = gs_p;
2473                                 }
2474                                 ngrps++;
2475                                 if (gs_p->breakbeam == YES && basictime > 8) {
2476                                         break;
2477                                 }
2478                         }
2479                         else {
2480                                 break;
2481                         }
2482                 }
2483
2484                 /* prepare to do next one */
2485                 if (gs_p != endbeam_p->next) {
2486                         gs_p = nxtbmgrp(gs_p, first_p, endbeam_p->next);
2487                 }
2488
2489                 /* if none we looked at deserved a beam, keep looking */
2490                 if (end_p == (struct GRPSYL *) 0) {
2491                         continue;
2492                 }
2493
2494                 /* calculate where on stem the beam should start */
2495                 y_offset = beam_offset(numbeams(basictime),
2496                                         begin_p->grpsize, begin_p->stemdir);
2497
2498                 if (end_p->grpsize == GS_NORMAL) {
2499                         halfwidth = W_WIDE * Staffscale / PPI / 2.0;
2500                         halfstem = W_NORMAL * Staffscale / PPI / 2.0;
2501                 }
2502                 else {
2503                         halfwidth = W_WIDE * Staffscale * SM_FACTOR / PPI / 2.0;
2504                         halfstem = W_NORMAL * Staffscale * SM_FACTOR / PPI / 2.0;
2505                 }
2506
2507                 /* check if single group.
2508                  * If so, need to do a partial beam, otherwise full beam */
2509                 if (ngrps == 1) {
2510                         /* rests and spaces don't get beams,
2511                          * so don't get partial ones */
2512                         if (end_p->grpcont != GC_NOTES) {
2513                                 continue;
2514                         }
2515
2516                         side = pbeamside(end_p, first_p);
2517
2518                         /* Now that we decided where the
2519                          * partial beam goes, we can draw it */
2520
2521                         /* in order to figure out the end point of the partial
2522                          * beam, we have to calculate the slope of the beam as
2523                          * if it were a full beam and derive from that where
2524                          * the partial beam will end. */
2525                         /* determine whether to use prev or next note, and
2526                          * skip any notes of the wrong type! */
2527                         if (side == PB_LEFT) {
2528                                 other_p = prevbmgrp(end_p, first_p);
2529                         }
2530                         else {
2531                                 other_p = nxtbmgrp(end_p, first_p, end_p->next);
2532                         }
2533
2534                         /* the line then goes from the stem (at y_offset) to
2535                          * a notehead width east or west of the stem,
2536                          * with the y coordinate calculated from the slope
2537                          * of what a full length beam would have been, unless
2538                          * stems are too close, in which case shorten it
2539                          * somewhat. */
2540                         x_begin = find_x_stem(end_p);
2541                         y_begin = find_y_stem(end_p);
2542                         x_other = find_x_stem(other_p);
2543                         y_other = find_y_stem(other_p);
2544
2545                         /* if cross-staff and the two stems are in opposite
2546                          * directions, have to compensate for that */
2547                         if (end_p->stemdir == other_p->stemdir) {
2548                                 /* in same direction */
2549                                 slope = (y_other - y_begin)
2550                                                         / (x_other - x_begin);
2551                         }
2552                         else {
2553                                 double opp_adj;
2554
2555                                 opp_adj = beam_offset(
2556                                         numbeams(other_p->basictime),
2557                                         other_p->grpsize, other_p->stemdir);
2558                                 slope = (y_other - (y_begin - opp_adj))
2559                                                         / (x_other - x_begin);
2560                         }
2561
2562                         /* adjust to overlap stem */
2563                         x_begin += halfstem * side;
2564
2565                         /* determine partial beam length */
2566                         /* find distance between stems */
2567                         if (x_begin < x_other) {
2568                                 stemdist = x_other - x_begin;
2569                         }
2570                         else {
2571                                 stemdist = x_begin - x_other;
2572                         }
2573                         /* if wide enough, use note head width, else less */
2574                         if (stemdist < 5.0 * Stepsize) {
2575                                 pbeam_len = 0.4 * stemdist;
2576                         }
2577                         else {
2578                                 pbeam_len = widest_head(end_p) * Staffscale;
2579                         }
2580
2581                         /* draw the partial beam */
2582                         do_beam(x_begin, y_begin + y_offset,
2583                                 x_begin + pbeam_len * side,
2584                                 y_begin + y_offset + side *
2585                                 pbeam_len * slope, halfwidth);
2586                 }
2587
2588                 else {
2589                         /* draw a normal beam */
2590
2591                         /* For regular beams, can use y_offset directly,
2592                          * but with cross-staff beam, stems may be in opposite
2593                          * directions, so have to call a function to get
2594                          * appropriate offset.
2595                          */
2596                         if (begin_p->beamto == CS_SAME) {
2597                                 end_y_offset = y_offset;
2598                         }
2599                         else {
2600                                 end_y_offset = end_bm_offset(first_p, end_p,
2601                                                                 basictime);
2602                         }
2603
2604                         /* If the stems on both ends of the beam
2605                          * are zero length, don't draw any beams.
2606                          * If user really wants the beams,
2607                          * they can make one of the ends
2608                          * barely longer than zero.
2609                          */
2610                         if (begin_p->stemlen <= 0.0 && end_p->stemlen <= 0.0) {
2611                                 continue;       
2612                         }
2613
2614                         /* find end of first stem and last stem and draw
2615                          * the beam at proper offset from there */
2616                         do_beam(find_x_stem(begin_p) - halfstem,
2617                                         find_y_stem(begin_p) + y_offset,
2618                                         find_x_stem(end_p) + halfstem,
2619                                         find_y_stem(end_p) + end_y_offset,
2620                                         halfwidth);
2621                 }
2622         }
2623         return(found);
2624 }
2625 \f
2626
2627 /* Figure out how far from the end of a stem a beam should be in the
2628  * case of a cross-staff beam with opposite-direction stems at its ends.
2629  * Will return some multiple (possibly 0) of the distance between beams,
2630  * with the proper sign to account for stem direction.
2631  * Should only be called if the beam in question is a cross-staff beam.
2632  */
2633
2634 double
2635 end_bm_offset(top_first_p, end_p, basictime)
2636
2637 struct GRPSYL *top_first_p;     /* the group that has "bm with staff below" */
2638 struct GRPSYL *end_p;           /* the group where a beam ends. This could be
2639                                  * either a group with ebm or some intermediate
2640                                  * group that happens to end a beam segment
2641                                  * that is shorter. */
2642 int basictime;                  /* the basictime of the beam currently under
2643                                  * consideration. The first beam drawn will
2644                                  * be 8, the next 16, then 32, etc. */
2645
2646 {
2647         static struct CSBINFO *csbi_list_p = 0;/* Info about the cross beams */
2648         static struct GRPSYL *cached_gs_p = 0;  /* Each time we get a different
2649                                  * top_first_p, we calculate its csbi_list
2650                                  * and cache it for future calls. This lets
2651                                  * us know if we can re-use the cached value. */
2652         struct CSBINFO *csbi_p; /* for walking 8th note beam ->next links */
2653         struct CSBINFO *c_p;    /* for walking vertical links of mesh */
2654         int nbeams;             /* how many beams from the stem end */
2655
2656         if (cached_gs_p != top_first_p) {
2657                 /* Cached one is no good; need to recalculate */
2658                 if (csbi_list_p != 0) {
2659                         /* We had a list before; need to clean it up */
2660                         struct CSBINFO *nextvert_p;     /* to free vert list */
2661                         struct CSBINFO *nexthor_p;      /* to free hor list */
2662                         /* walk horizontal list */
2663                         for (csbi_p = csbi_list_p; csbi_p != 0;
2664                                                         csbi_p = nexthor_p) {
2665                                 /* clean up vert list, both directions */
2666                                 for (c_p = csbi_p->above_p; c_p != 0;
2667                                                         c_p = nextvert_p) {
2668                                         nextvert_p = c_p->above_p;
2669                                         FREE(c_p);
2670                                 }
2671                                 for (c_p = csbi_p->below_p; c_p != 0;
2672                                                         c_p = nextvert_p) {
2673                                         nextvert_p = c_p->below_p;
2674                                         FREE(c_p);
2675                                 }
2676                                 nexthor_p = csbi_p->next;
2677                                 FREE(csbi_p);
2678                         }
2679                 }
2680                 /* Calculate everything for current beam */
2681                 csbi_list_p = mkcsbmesh(top_first_p, end_p);
2682                 cached_gs_p = top_first_p;
2683         }
2684
2685         /* First follow the 8th note CSBINFO list across till we find
2686          * the one matching the end group. */
2687         for (csbi_p = csbi_list_p; csbi_p != 0 && csbi_p->gs_p != end_p;
2688                                                         csbi_p = csbi_p->next) {
2689                 ;
2690         }
2691         if (csbi_p == 0) {
2692                 pfatal("couldn't find beam end group in end_bm_offset()");
2693         }
2694
2695         /* Now follow the vertical links until we find the right basic time.
2696          * It could be on either side of the 8th beam.
2697          * First we find the end of the stem, then count the number of
2698          * links we have to follow to get to the one with the right basictime.
2699          */
2700         if (end_p->stemdir == DOWN) {
2701                 /* Must be from staff above, so end of stem is all the way                       * down the below_p list.
2702                  */
2703                 for (c_p = csbi_p; c_p->below_p != 0; c_p = c_p->below_p) {
2704                         ;
2705                 }
2706                 /* Now count the number of beams till the one we want */
2707                 for (nbeams = 1; c_p->basictime != basictime;
2708                                                         c_p = c_p->above_p) {
2709                         nbeams++;
2710                 }
2711                 if (c_p == 0) {
2712                         pfatal("failed to find cross staff beam info go up");
2713                 }
2714         }
2715         else {
2716                 /* similar for staff below groups */
2717                 for (c_p = csbi_p; c_p->above_p != 0; c_p = c_p->above_p) {
2718                         ;
2719                 }
2720                 /* Now count the number of beams till the one we want */
2721                 for (nbeams = 1; c_p->basictime != basictime;
2722                                                         c_p = c_p->below_p) {
2723                         nbeams++;
2724                 }
2725                 if (c_p == 0) {
2726                         pfatal("failed to find cross staff beam info go up");
2727                 }
2728         }
2729         return (beam_offset(nbeams, end_p->grpsize, end_p->stemdir));
2730 }
2731 \f
2732
2733 /* find y offset on stem based on number of beams, whether normal or small
2734  * notes, and stem direction */
2735
2736 static double
2737 beam_offset(nbeams, gsize, stemdir)
2738
2739 int nbeams;     /* how many beams */
2740 int gsize;      /* GS_NORMAL or GS_SMALL */
2741 int stemdir;    /* UP or DOWN */
2742
2743 {
2744         /* for consistency, it would be nice to use FLAGSEP and SMFLAGSEP
2745          * for beam separation too, but when we tried that, beams looked too
2746          * close together, especially on certain low-resolution devices,
2747          * so that's why we're using 5 and 4 stepsizes. */
2748         return ( (nbeams - 1) * (gsize == GS_NORMAL ? 5.0 : 4.0)
2749                                         * Staffscale
2750                                         * (stemdir == UP ? -POINT : POINT) );
2751 }
2752 \f
2753
2754 /* Given a group inside a beam, return the next group. Usually this will
2755  * be gs_p->next, but in the case of a cross-staff beam, it might be a
2756  * group on the other staff */
2757
2758 struct GRPSYL *
2759 nxtbmgrp(gs_p, first_p, endnext_p)
2760
2761 struct GRPSYL *gs_p;            /* find the beam group after this one */
2762 struct GRPSYL *first_p;         /* The first group in the top staff of the
2763                                  * beam */
2764 struct GRPSYL *endnext_p;       /* what to return upon reaching the end of
2765                                  * the beam. This will be the ->next field of
2766                                  * the last group in the beam on the top staff
2767                                  * of a cross-staff beam. Returning this lets
2768                                  * legacy code (code before we supported
2769                                  * cross-staff beams) keep working with minimal
2770                                  * changes. */
2771
2772 {
2773         int grpsize, grpvalue;
2774
2775         /* If we are passed the first group, it could be a space,
2776          * in which case we need to use the below staff's group instead.
2777          */
2778         if (gs_p->grpcont == GC_SPACE && gs_p->beamto != CS_SAME) {
2779                 /* Need to hop to below staff. Go down the chord to find
2780                  * the matching cross-staff beam group. */
2781                 do {
2782                         if ((gs_p = gs_p->gs_p) == (struct GRPSYL *) 0) {
2783                                 pfatal("can't find matching beam chord");
2784                         }
2785
2786                 /* skip any lyrics and such till we find the beamed-to group */
2787                 } while (gs_p->beamto != CS_ABOVE);
2788         }
2789
2790         /* need to skip past any groups of the wrong kind */
2791         grpsize = first_p->grpsize;
2792         grpvalue = first_p->grpvalue;
2793         do {
2794                 /* Move to next group. If that gets us to the end
2795                  * of the measure, report that we're done. */
2796                 if ((gs_p = gs_p->next) == (struct GRPSYL *) 0) {
2797                         return(endnext_p);
2798                 }
2799         } while (gs_p->grpsize != grpsize || gs_p->grpvalue != grpvalue);
2800
2801         /* if past end of beam group, report that we're done */
2802         if (gs_p->beamloc != INITEM && gs_p->beamloc != ENDITEM) {
2803                 return(endnext_p);
2804         }
2805
2806         return(neighboring_note_beam_group(gs_p, first_p, NO));
2807 }
2808 \f
2809
2810 /* Given a group inside a beam (not the first),
2811  * return the previous group. Usually this will
2812  * be gs_p->prev, but in the case of a cross-staff beam, it might be a
2813  * group on the other staff */
2814
2815 struct GRPSYL *
2816 prevbmgrp(gs_p, first_p)
2817
2818 struct GRPSYL *gs_p;            /* find the beam group after this one */
2819 struct GRPSYL *first_p;         /* The first group in the top staff of the
2820                                  * beam */
2821
2822 {
2823         int grpsize, grpvalue;
2824         int staffno;
2825
2826         staffno = gs_p->staffno;
2827
2828         /* need to skip past any groups of the wrong kind */
2829         grpsize = first_p->grpsize;
2830         grpvalue = first_p->grpvalue;
2831         do {
2832                 /* Move to prev group. */
2833                 if ((gs_p = gs_p->prev) == (struct GRPSYL *) 0) {
2834                         pfatal("prevbmgrp couldn't find prev group");
2835                 }
2836         } while (gs_p->grpsize != grpsize || gs_p->grpvalue != grpvalue);
2837
2838         gs_p = neighboring_note_beam_group(gs_p, first_p, YES);
2839
2840         /* if we hopped staffs, then the space on the original staff might
2841          * have been a long note, in which case the group we have isn't
2842          * really the one we want. So we have to go forward on this new staff
2843          * until we find the space that corresponds to the groups we started
2844          * with, then back up one group from there. That's the one we want */
2845         if (staffno != gs_p->staffno) {
2846                 /* we hopped staffs. Go forward to the next space */
2847                 for (gs_p = gs_p->next; gs_p->grpcont != GC_SPACE;
2848                                                         gs_p = gs_p->next) {
2849                         ;
2850                 }
2851                 /* now take the group right before the space */
2852                 gs_p = gs_p->prev;
2853         }
2854         return(gs_p);
2855 }
2856 \f
2857
2858 /* Given a group in a beam, skip over any embedded rests.
2859  * Then if the group is not a space, return it as it is.
2860  * If it is a space, return the corresponding group on the staff
2861  * that this group is beamed to */
2862
2863 static struct GRPSYL *
2864 neighboring_note_beam_group(gs_p, first_p, backwards)
2865
2866 struct GRPSYL *gs_p;            /* find the beam group neighboring this one */
2867 struct GRPSYL *first_p;         /* The first group in the top staff of the
2868                                  * beam */
2869 int backwards;                  /* if YES, go backwards (find the previous
2870                                  * group rather than the following) */
2871
2872 {
2873         struct GRPSYL *tgs_p;   /* as we walk down a chord to try to find
2874                                  * the group we're looking for, this keeps
2875                                  * track of where we are */
2876
2877
2878         /* skip over any embedded rests--they are not notes. */
2879         while (gs_p->grpcont == GC_REST) {
2880                 if (backwards == YES) {
2881                         gs_p = gs_p->prev;
2882                 }
2883                 else {
2884                         gs_p = gs_p->next;
2885                 }
2886         }
2887         if (gs_p == 0) {
2888                 pfatal("neighboring_note_beam_group didn't find note group");
2889         }
2890
2891         /* If this is a cross-staff beam, we may need to hop from
2892          * staff to staff sometimes. If this group is a space
2893          * group, then we have to hop now. */
2894         if (gs_p->grpcont == GC_SPACE) {
2895                 if (gs_p->beamto == CS_SAME) {
2896                         do {
2897                                 if (backwards == YES) {
2898                                         gs_p = gs_p->prev;
2899                                 } else {
2900                                         gs_p = gs_p->next;
2901                                 }
2902                         } while (gs_p != 0 && gs_p->grpcont != GC_NOTES);
2903                 }
2904
2905                 else if (gs_p->staffno == first_p->staffno) {
2906                         /* Need to hop to below staff.
2907                          * Go down the chord to find
2908                          * the matching cross-staff beam group */
2909                         do {
2910                                 if ((gs_p = gs_p->gs_p) ==
2911                                                 (struct GRPSYL *) 0) {
2912                                         pfatal("can't find matching beam chord");
2913                                 }
2914
2915                         /* skip any lyrics and such till we find the
2916                          * group beamed to us */
2917                         } while (gs_p->beamto != CS_ABOVE);
2918                 }
2919                 else {
2920                         /* Need to jump back to staff above.
2921                          * Since the chord linked list is only one way (down)
2922                          * and we need to look up the chord, this is a
2923                          * little harder. Start at the first_p group, which
2924                          * is the first group in the beam on the above staff.
2925                          * Keep going down that staff until we find a chord
2926                          * linked down to gs_p. */
2927                         for (   ; first_p != (struct GRPSYL *) 0;
2928                                                 first_p = first_p->next) {
2929
2930                                 /* walk down the chord */
2931                                 for (tgs_p = first_p->gs_p;
2932                                                 tgs_p != (struct GRPSYL *) 0;
2933                                                 tgs_p = tgs_p->gs_p) {
2934
2935                                         if (tgs_p == gs_p) {
2936                                                 /* Aha! We found it! */
2937                                                 return(first_p);
2938                                         }
2939
2940                                         if (tgs_p->staffno > gs_p->staffno) {
2941                                                 /* we're past the staff we care
2942                                                  * about, so this chord can't
2943                                                  * be the right one. */
2944                                                 break;
2945                                         }
2946                                 }
2947                         }
2948
2949                         pfatal("failed to find group when jumping back to above staff");
2950                 }
2951         }
2952
2953         return(gs_p);
2954 }
2955 \f
2956
2957 /* given a GRPSYL that deserves a partial beam, return PB_LEFT if the beam
2958  * goes on the left or PB_RIGHT if is goes on the right.  */
2959
2960 int
2961 pbeamside(gs_p, first_p)
2962
2963 struct GRPSYL *gs_p;
2964 struct GRPSYL *first_p;
2965
2966 {
2967         int side;
2968         int beams2left, beams2right;    /* how many beams or dots for notes on
2969                                          * either side of current group */
2970         struct GRPSYL *prevgs_p, *nextgs_p;
2971
2972
2973         /* need to figure out which side of stem to draw the
2974          * partial beam. First the easy cases: if is STARTITEM,
2975          * then it has to go on the right, if ENDITEM, it
2976          * has to go on the left */
2977         switch (gs_p->beamloc) {
2978         case STARTITEM:
2979                 side = PB_RIGHT;
2980                 break;
2981
2982         case ENDITEM:
2983                 side = PB_LEFT;
2984                 break;
2985
2986         case INITEM:
2987                 /* Hmmm. Will have to be more clever. Check the
2988                  * note on either side. If we're at a breakbeam,
2989                  * it's easy to know. Otherwise, if one should have more
2990                  * beams than the other, put the partial on that
2991                  * side */
2992                 prevgs_p = prevbmgrp(gs_p, first_p);
2993                 nextgs_p = nxtbmgrp(gs_p, first_p, gs_p->next);
2994                 beams2left = numbeams(prevgs_p->basictime);
2995                 beams2right = numbeams(nextgs_p->basictime);
2996                 if (gs_p->breakbeam == YES) {
2997                         side = PB_LEFT;
2998                 }
2999                 else if (prevgs_p != 0 && prevgs_p->breakbeam == YES) {
3000                         side = PB_RIGHT;
3001                 }
3002                 else if (beams2left > beams2right) {
3003                         side = PB_LEFT;
3004                 }
3005                 else if (beams2right > beams2left) {
3006                         side = PB_RIGHT;
3007                 }
3008
3009                 /* That was inconclusive.  So now we're going to try to decide
3010                  * based on logical groupings of notes; that is, notes grouped
3011                  * according to what the accents should be. */
3012                 else if (chkgroupings(&side, gs_p) == YES) {
3013                         /* it found an answer and set "side" for us */
3014                         ;
3015                 }
3016                 else {
3017                         /* ok. that didn't help.
3018                          * See if the notes on either side
3019                          * have more dots than the other.
3020                          * If so, put the partial towards
3021                          * that one. If they are the same, then
3022                          * throw in the towel and just stick it
3023                          * on the left */
3024                         beams2left = prevgs_p->dots;
3025                         beams2right = nextgs_p->dots;
3026                         if (beams2right > beams2left) {
3027                                 side = PB_RIGHT;
3028                         }
3029                         else {
3030                                 side = PB_LEFT;
3031                         }
3032                 }
3033                 break;
3034
3035         default:
3036                 pfatal("invalid beamloc passed to pbeamside");
3037                 /*NOTREACHED*/
3038                 return(PB_LEFT);        /* to shut up bogus compiler warning */
3039         }
3040
3041         return(side);
3042 }
3043 \f
3044 /*
3045  * Name:        chkgroupings()
3046  *
3047  * Abstract:    Decide partial beam side based on groupings of notes.
3048  *
3049  * Returns:     YES if it found an answer (stored in *side_p), NO if not
3050  *
3051  * Description: This function breaks the measure down into successively
3052  *              smaller pieces based on where the accents should be, trying to
3053  *              find a piece where the current GRPSYL falls at the beginning or
3054  *              end of the piece.  If the GRPSYL falls at the start of a piece,
3055  *              its partial beam should point right; if end, left.  If we get
3056  *              to the point where the pieces are shorter than the GRPSYL
3057  *              itself, we have failed.
3058  */
3059
3060 static int
3061 chkgroupings(side_p, thisgs_p)
3062
3063 int *side_p;                    /* where to put the answer, if found */
3064 struct GRPSYL *thisgs_p;        /* the GRPSYL we are working on */
3065
3066 {
3067         struct GRPSYL *gs_p;    /* point along GRPSYL list */
3068         short *factors;         /* array to be malloc'ed */
3069         int n;                  /* loop variable */
3070         RATIONAL thisstart;     /* time offset in measure of thisgs_p */
3071         RATIONAL nextstart;     /* time offset in measure of next GRPSYL */
3072         RATIONAL quotient;      /* temp variable for dividing */
3073         RATIONAL grouplen;      /* time length of a grouping */
3074         RATIONAL tupstart;      /* time offset where tuplet starts */
3075         RATIONAL tupdur;        /* time length of a tuplet */
3076         int counts;             /* count in the current grouplen */
3077         int fraction;           /* is grouplen a fraction of a count? */
3078         int fact;               /* a factor */
3079
3080
3081         /*
3082          * If we're doing grace beams, skip this whole thing, since we're
3083          * dealing with time values, and they are all zero.
3084          */
3085         if (thisgs_p->grpvalue == GV_ZERO) {
3086                 return (NO);
3087         }
3088
3089         /* find the time offset of thisgs_p by adding up all previous GRPSYLs*/
3090         thisstart = Zero;
3091         for (gs_p = thisgs_p->prev; gs_p != 0; gs_p = gs_p->prev) {
3092                 thisstart = radd(thisstart, gs_p->fulltime);
3093         }
3094
3095         /* find offset of GRPSYL following thisgs_p */
3096         nextstart = radd(thisstart, thisgs_p->fulltime);
3097
3098         /*
3099          * Interior notes of tuplets are dealt with in a special way.
3100          */
3101         if (thisgs_p->tuploc == INITEM) {
3102                 /*
3103                  * Find the duration of the tuplet by adding up all the
3104                  * previous GRPSYLs in the tuplet and this GRPSYL and all the
3105                  * later GRPSYLs.  (The loops stop when they hit a NOITEM
3106                  * that's not grace.)
3107                  */
3108                 tupdur = Zero;
3109                 for (gs_p = thisgs_p->prev; gs_p != 0 &&
3110                                 (gs_p->grpvalue == GV_ZERO ||
3111                                 gs_p->tuploc != NOITEM); gs_p = gs_p->prev) {
3112                         tupdur = radd(tupdur, gs_p->fulltime);
3113                 }
3114                 /* remember where tuplet starts */
3115                 tupstart = rsub(thisstart, tupdur);
3116                 for (gs_p = thisgs_p; gs_p != 0 &&
3117                                 (gs_p->grpvalue == GV_ZERO ||
3118                                 gs_p->tuploc != NOITEM); gs_p = gs_p->next) {
3119                         tupdur = radd(tupdur, gs_p->fulltime);
3120                 }
3121
3122                 /*
3123                  * If the starting point of this tuplet is not at a multiple of
3124                  * its duration, we consider the tuplet synchopated.  This is
3125                  * pretty bizarre and not worth trying to deal with.
3126                  */
3127                 quotient = rdiv(tupstart, tupdur);
3128                 if (quotient.d != 1) {
3129                         return (NO);
3130                 }
3131
3132                 /* the first group length to consider is tupdur/tupcont */
3133                 grouplen = tupdur;
3134                 grouplen.d *= thisgs_p->tupcont;
3135                 rred(&grouplen);
3136
3137                 /* loop until an answer is found, or we give up */
3138                 for (;;) {
3139                         /*
3140                          * If the group length is not longer than our note, it
3141                          * makes no sense to try to see if our note is at the
3142                          * start or end of such a group.  Maybe we never hit a
3143                          * match because our note is syncopated.  Whatever the
3144                          * reason, we have to give up.
3145                          */
3146                         if (LE(grouplen, thisgs_p->fulltime)) {
3147                                 return (NO);
3148                         }
3149
3150                         /*
3151                          * If thisstart/grouplen is an integer, it means
3152                          * thisgs_p is on a grouping boundary; that is, it is
3153                          * the first GRPSYL in a grouping.  So point right.
3154                          */
3155                         quotient = rdiv(thisstart, grouplen);
3156                         if (quotient.d == 1) {
3157                                 *side_p = PB_RIGHT;
3158                                 return (YES);
3159                         }
3160
3161                         /*
3162                          * If nextstart/grouplen is an integer, it means the
3163                          * GRPSYL after thisgs_p is on a grouping boundary,
3164                          * which means that thisgs_p is the last GRPSYL in a
3165                          * grouping.  So point left.
3166                          */
3167                         quotient = rdiv(nextstart, grouplen);
3168                         if (quotient.d == 1) {
3169                                 *side_p = PB_LEFT;
3170                                 return (YES);
3171                         }
3172
3173                         /* divide grouplen by 2 and try again */
3174                         grouplen = rdiv(grouplen, Two);
3175                 }
3176         }
3177
3178         /*
3179          * This is the normal case, not the interior of a tuplet.
3180          */
3181
3182         /* get all the prime factors of the time sig's numerator */
3183         factors = factor(Score.timenum);
3184
3185         grouplen = Score.time;          /* first group is the whole measure */
3186         counts = Score.timenum;         /* number of counts in measure */
3187
3188         /*
3189          * Loop until we find an answer, or until we have to give up.  Each
3190          * time through the loop, we reduce the grouping length.  At first, we
3191          * divide out prime factors from the number of counts in the measure.
3192          * Once we get down to one count, we start dividing by 2 all the time.
3193          */
3194         for (;;) {
3195                 fraction = YES;         /* default to "fraction of a count" */
3196
3197                 /* if there are still multiple counts, divide out a prime */
3198                 if (counts > 1) {
3199                         /*
3200                          * See if there are any prime factors greater than 4.
3201                          * This only happens with funny timesigs like 10/8 or
3202                          * 7/4.  We work down from the top, because the
3203                          * likelyhood is that the highest level grouping is by
3204                          * the biggest factor, when these funny numbers are
3205                          * involved.  At least 10/8, for example, is normally
3206                          * 5 groups of 2, not 2 groups of 5.
3207                          */
3208                         for (n = Score.timenum; n > 4 && factors[n] == 0; n--)
3209                                 ;
3210                         /* if we found a 5 or greater, use it */
3211                         if (n > 4) {
3212                                 factors[n]--;
3213                                 fact = n;
3214                         /*
3215                          * There are no funny factors (5 or more) left.  Next,
3216                          * we need to look for 2s, not 3s yet, because, for
3217                          * example, 6/8 is 2 groups of 3, not 3 groups of 2.
3218                          */
3219                         } else if (counts % 2 == 0) {
3220                                 factors[2]--;
3221                                 fact = 2;
3222                         /* no 2s either, so look for 3s */
3223                         } else if (counts % 3 == 0) {
3224                                 factors[3]--;
3225                                 fact = 3;
3226                         } else {
3227                         /* no factors left, so flag it by setting fact to 1 */
3228                                 fact = 1;
3229                         }
3230
3231                         /*
3232                          * If a factor was found, divide it out, and remember
3233                          * that we are not yet dealing with fractions of a
3234                          * single count.
3235                          */
3236                         if (fact > 1) {
3237                                 counts /= fact;
3238                                 fraction = NO;
3239                         }
3240                 }
3241
3242                 if (fraction == YES) {
3243                         /*
3244                          * We are dealing with fractions of a count, so divide
3245                          * by 2 from now on.
3246                          */
3247                         grouplen = rdiv(grouplen, Two);
3248                 } else {
3249                         /*
3250                          * Using the number of counts remaining, form the
3251                          * length in lowest terms.
3252                          */
3253                         grouplen.n = counts;
3254                         grouplen.d = Score.timeden;
3255                         rred(&grouplen);
3256                 }
3257
3258                 /*
3259                  * If the group length is not longer than our note, it makes no
3260                  * sense to try to see if our note is at the start or end of
3261                  * such a group.  Maybe we never hit a match because our note
3262                  * is syncopated.  Whatever the reason, we have to give up.
3263                  */
3264                 if (LE(grouplen, thisgs_p->fulltime)) {
3265                         return (NO);
3266                 }
3267
3268                 /*
3269                  * If thisstart/grouplen is an integer, it means thisgs_p is on
3270                  * a grouping boundary; that is, it is the first GRPSYL in a
3271                  * grouping.  So point right.
3272                  */
3273                 quotient = rdiv(thisstart, grouplen);
3274                 if (quotient.d == 1) {
3275                         *side_p = PB_RIGHT;
3276                         return (YES);
3277                 }
3278
3279                 /*
3280                  * If nextstart/grouplen is an integer, it means the GRPSYL
3281                  * after thisgs_p is on a grouping boundary, which means that
3282                  * thisgs_p is the last GRPSYL in a grouping.  So point left.
3283                  */
3284                 quotient = rdiv(nextstart, grouplen);
3285                 if (quotient.d == 1) {
3286                         *side_p = PB_LEFT;
3287                         return (YES);
3288                 }
3289         }
3290
3291         return (NO);            /* we can never get here; this is for lint */
3292 }
3293 \f
3294
3295 /* actually draw a beam */
3296
3297 static void
3298 do_beam(x1, y1, x2, y2, halfwidth)
3299
3300 double x1, y1;          /* start beam here */
3301 double x2, y2;          /* end beam here */
3302 double halfwidth;       /* go this far up and down from y1 and y2 to get
3303                          * corners of parallelogram that makes up the beam */
3304
3305 {
3306         do_newpath();
3307         do_moveto(x1, y1 + halfwidth);
3308         do_line(x2, y2 + halfwidth);
3309         do_line(x2, y2 - halfwidth);
3310         do_line(x1, y1 - halfwidth);
3311         do_closepath();
3312         do_fill();
3313 }
3314 \f
3315
3316 /* print a multirest */
3317
3318 void
3319 pr_multirest(gs_p, staff_p)
3320
3321 struct GRPSYL *gs_p;    /* info about the multirest */
3322 struct STAFF *staff_p;
3323
3324 {
3325         double x;               /* horizontal position of number string */
3326         double y, y_offset;     /* vertical location */
3327         double height, width;   /* of meas num string */
3328         float east, west;       /* edges of the multirest */
3329         char *numstr;           /* ASCII version of numbers of measures */
3330
3331
3332         /* avoid core dumps */
3333         if (Score_location_p == (float *) 0) {
3334                 pfatal("can't do multirest: no feed");
3335                 return;
3336         }
3337
3338         /* determine where to place the multirest */
3339         y = mr_y_loc(gs_p->staffno);
3340         east = gs_p->c[AE];
3341         west = gs_p->c[AW];
3342
3343         /* If user wants us to use the alternative multirest style of using
3344          * rest symbols (often used in orchestral music), and the length of
3345          * the multirest is 8 or less, we use that alternate style,
3346          * otherwise draw horizontal line along middle staff and two
3347          * vertical lines near the bar lines. Note that the basictime is
3348          * the negative of the number of measures of multirest.  
3349          * We have seen rare examples of using the alternate style for all the
3350          * way up to 11 measures, but consider normal usage only up to 8.
3351          */
3352         if (svpath(staff_p->staffno, RESTSYMMULT)->restsymmult == YES &&
3353                                                 gs_p->basictime > -9) {
3354                 double center;  /* can't use AX, must use avg of AE and AW */
3355                 int size;       /* actually will always be normal size,
3356                                  * but may as well make code be able to handle
3357                                  * small size just in case... */
3358
3359                 center = (gs_p->c[AE] + gs_p->c[AW]) / 2.0;
3360                 size = (gs_p->grpsize == GS_NORMAL ? DFLT_SIZE : SMALLSIZE);
3361
3362                 switch (gs_p->basictime) {
3363                 case -2:
3364                         pr_muschar(center, gs_p->c[AY], C_DWHREST, size, FONT_MUSIC);
3365                         break;
3366                 case -3:
3367                         pr_muschar(gs_p->c[AW], gs_p->c[AY], C_DWHREST, size, FONT_MUSIC);
3368                         pr_muschar(gs_p->c[AE], gs_p->c[AY], C_1REST, size, FONT_MUSIC);
3369                         break;
3370                 case -4:
3371                         pr_muschar(center, gs_p->c[AY], C_QWHREST, size, FONT_MUSIC);
3372                         break;
3373                 case -5:
3374                         pr_muschar(gs_p->c[AW], gs_p->c[AY], C_QWHREST, size, FONT_MUSIC);
3375                         pr_muschar(gs_p->c[AE], gs_p->c[AY], C_1REST, size, FONT_MUSIC);
3376                         break;
3377                 case -6:
3378                         pr_muschar(gs_p->c[AW], gs_p->c[AY], C_QWHREST, size, FONT_MUSIC);
3379                         pr_muschar(gs_p->c[AE], gs_p->c[AY], C_DWHREST, size, FONT_MUSIC);
3380                         break;
3381                 case -7:
3382                         pr_muschar(gs_p->c[AW], gs_p->c[AY], C_QWHREST, size, FONT_MUSIC);
3383                         pr_muschar(center, gs_p->c[AY], C_DWHREST, size, FONT_MUSIC);
3384                         pr_muschar(gs_p->c[AE], gs_p->c[AY], C_1REST, size, FONT_MUSIC);
3385                         break;
3386                 case -8:
3387                         pr_muschar(gs_p->c[AW], gs_p->c[AY], C_QWHREST, size, FONT_MUSIC);
3388                         pr_muschar(gs_p->c[AE], gs_p->c[AY], C_QWHREST, size, FONT_MUSIC);
3389                         break;
3390                 default:
3391                         pfatal("restsymmult with illegal number of measures (%d)",
3392                                         -(gs_p->basictime) );
3393                         break;
3394                 }
3395         }
3396         else {
3397                 /* draw vertical lines at each end */
3398                 do_linetype(L_MEDIUM);
3399
3400                 draw_line(west, y - (2.0 * Stepsize), west, y + (2.0 * Stepsize));
3401                 draw_line(east, y - (2.0 * Stepsize), east, y + (2.0 * Stepsize));
3402
3403                 /* draw heavy horizontal */
3404                 do_linetype(L_WIDE);
3405                 draw_line(west, y, east, y);
3406         }
3407
3408         if (svpath(staff_p->staffno, PRINTMULTNUM)->printmultnum == YES) {
3409                 /* print number of measures */
3410                 numstr = mrnum(staff_p, &x, &y_offset, &height, &width);
3411                 pr_string(x, y + y_offset, numstr, J_LEFT, (char *) 0, -1);
3412         }
3413 }
3414 \f
3415
3416 /* Given a STAFF pointing to a multirest or measure repeat GRPSYL,
3417  * return a string for its number of measures,
3418  * and return via pointers its x, relative y, height, and width */
3419
3420 char *
3421 mrnum(staff_p, x_p, y_offset_p, height_p, width_p)
3422
3423 struct STAFF *staff_p;
3424 double *x_p;            /* return where number starts horizontally */
3425 double *y_offset_p;     /* return y relative to staff */
3426 double *height_p;       /* return height of string */
3427 double *width_p;        /* return width of string */
3428
3429 {
3430         struct GRPSYL *gs_p = 0;/* initialize to avoid compiler warning */
3431         char *numstr;           /* ASCII version of number of measures */
3432         int v;                  /* voice index */
3433
3434         /* skip over invisible voices */
3435         for (v = 0; v < MAXVOICES; v++) {
3436                 if (vvpath(staff_p->staffno, v + 1, VISIBLE)->visible == YES) {
3437                         gs_p = staff_p->groups_p[v];
3438                         break;
3439                 }
3440         }
3441         if (v == MAXVOICES) {
3442                 pfatal("no visible voice found by mrnum");
3443         }
3444         if (gs_p->grpcont == GC_NOTES) {
3445                 /* this is a measure repeat */
3446                 numstr = num2str(staff_p->mrptnum);
3447                 numstr[0] = FONT_TR;
3448                 numstr[1] = 11;
3449         }
3450         else if (gs_p->grpcont == GC_REST) {
3451                 /* this is a multi-rest */
3452                 numstr = num2str( -(gs_p->basictime) );
3453                 /* want these in bigger size */
3454                 /* Essential Dictionary of Music Notation says this
3455                  * should be in the same size and font as time signature. */
3456                 numstr[0] = FONT_NB;
3457                 numstr[1] = 16;
3458         }
3459         else {
3460                 pfatal("wrong group type (%d) passed to mrnum, line %d, staff %d, voice %d", gs_p->grpcont, gs_p->inputlineno, gs_p->staffno, gs_p->vno);
3461                 /*NOTREACHED*/
3462                 return (char *) 0;      /* to shut up bogus compiler warning */
3463         }
3464         numstr[1] = (char) adj_size((int) numstr[1], Staffscale, (char *) 0, -1);
3465
3466         *width_p = strwidth(numstr);
3467         *height_p = strheight(numstr);
3468
3469         /* x is middle of measure minus 1/2 of number string width */
3470         /* y offset is just above staff */
3471         *x_p = ((gs_p->c[AE] + gs_p->c[AW]) / 2.0) - (*width_p / 2.0);
3472         *y_offset_p = halfstaffhi(gs_p->staffno) + Stepsize;
3473         return(numstr);
3474 }
3475 \f
3476
3477 /* given a number, return pointer to string version (with font/size in first
3478  * 2 bytes. Points to static area overwritten on each call, so if you need a
3479  * unique copy of it, use copy_string(). Always makes a string in Roman in
3480  * the default size. */
3481
3482 char *
3483 num2str(num)
3484
3485 int num;        /* the number to convert */
3486
3487 {
3488         static char numstr[12];
3489
3490         /* get ASCII version of number */
3491         (void) sprintf(numstr, "%c%c%d", FONT_TR,
3492                         adj_size(DFLT_SIZE, Staffscale, (char *) 0, -1), num);
3493         return(numstr);
3494 }
3495 \f
3496
3497 /* print cresc or decresc */
3498
3499 static void
3500 pr_cresc(stuff_p)
3501
3502 struct STUFF *stuff_p;  /* info about what to print and where */
3503
3504 {
3505         float x1, x2;                   /* x coords of west and east points */
3506         float line1y1, line2y1;         /* y coords of west points */
3507         float line1y2, line2y2;         /* y coords of east points */
3508
3509
3510         do_linetype(L_NORMAL);
3511
3512         /* get coords for point and midpoint of open end */
3513         x1 = stuff_p->c[AW];
3514         x2 = stuff_p->c[AE];
3515         if (stuff_p->stuff_type == ST_CRESC) {
3516                 line1y1 = line2y1 = (stuff_p->c[AN] + stuff_p->c[AS]) / 2.0;
3517                 /* adjust by 1 point to allow some vertical padding */
3518                 line1y2 = stuff_p->c[AN] - (1.0 * Stdpad);
3519                 line2y2 = stuff_p->c[AS] + (1.0 * Stdpad);
3520         }
3521         else if (stuff_p->stuff_type == ST_DECRESC) {
3522                 line1y2 = line2y2 = (stuff_p->c[AN] + stuff_p->c[AS]) / 2.0;
3523                 line1y1 = stuff_p->c[AN] - (1.0 * Stdpad);
3524                 line2y1 = stuff_p->c[AS] + (1.0 * Stdpad);
3525         }
3526         else {
3527                 pfatal("pr_cres called for something other than cresc/decresc");
3528                 /*NOTREACHED*/
3529                 return; /* to shut up bogus compiler warning about unused variables */
3530         }
3531
3532         /* draw the two sides of the hairpin */
3533         draw_line(x1, line1y1, x2, line1y2);
3534         draw_line(x1, line2y1, x2, line2y2);
3535 }
3536 \f
3537
3538 /* if a STUFF has a til clause, may need to extend out. If a trill, extend
3539  * with wavy line. If octave, use dashed line.  If strings ends with a ~,
3540  * use a wavy line. If ends with an underscore or is figbass, use
3541  * underline. For everything else, put out periodic dashed. */
3542
3543 static void
3544 extend(stuff_p)
3545
3546 struct STUFF *stuff_p;  /* a stuff which may have a til clause */
3547
3548 {
3549         float extlen;           /* length of extension */
3550         float y;                /* vertical position */
3551         float x;                /* horizontal position */
3552         float segment;          /* length of dash + white space */
3553         char *dash;             /* dash in proper font/size */
3554         char lch;               /* last character of string */
3555
3556
3557         if (stuff_p->end.bars <= 0 && stuff_p->end.count <= 0.0) {
3558                 /* no til clause, so nothing to do */
3559                 return;
3560         }
3561
3562         /* figure out how much to extend */
3563         extlen = stuff_p->c[AE] - stuff_p->c[AW] - strwidth(stuff_p->string);
3564         y = stuff_p->c[AY];
3565
3566         if (string_is_sym(stuff_p->string, C_TR, FONT_MUSIC) == YES) {
3567                 /* special case of a trill */
3568                 if ( extlen < Stepsize) {
3569                         /* too short to bother */
3570                         return;
3571                 }
3572
3573                 y += (2.0 * Stepsize);
3574                 draw_wavy(stuff_p->c[AE] - extlen, y, stuff_p->c[AE], y);
3575                 return;
3576         }
3577
3578         else if ((lch = last_char(stuff_p->string)) == '~') {
3579                 y += strascent(stuff_p->string) / 2.0;
3580                 draw_wavy(stuff_p->c[AE] - extlen, y, stuff_p->c[AE], y);
3581                 return;
3582         }
3583
3584         else if (lch == '_' || stuff_p->modifier == TM_FIGBASS) {
3585                 do_linetype(L_NORMAL);
3586                 draw_line(stuff_p->c[AE] - extlen, y, stuff_p->c[AE], y);
3587                 return;
3588         }
3589
3590         else if (stuff_p->stuff_type == ST_OCTAVE) {
3591
3592                 if ( extlen < (4.0 * Stepsize)) {
3593                         /* too short to bother */
3594                         return;
3595                 }
3596
3597                 y += (1.5 * Stepsize);
3598                 do_linetype(L_DASHED);
3599                 draw_line(stuff_p->c[AE] - extlen + (2.0 * Stepsize), y,
3600                                                 stuff_p->c[AE], y);
3601
3602                 /* vertical line at end unless carried to next score */
3603                 if (stuff_p->carryout == NO) {
3604                         draw_line(stuff_p->c[AE], y, stuff_p->c[AE],
3605                                 y + (3.0 * Stepsize *
3606                                 (stuff_p->place == PL_ABOVE ? -1.0 : 1.0)));
3607                 }
3608
3609                 /* put linetype back to solid so some other music character that
3610                  * uses a line won't get messed up */
3611                 do_linetype(L_NORMAL);
3612                 return;
3613         }
3614
3615         dash = dashstr(stuff_p->string);
3616         segment = (3.0 * strwidth(dash));
3617         for ( x = stuff_p->c[AE] - extlen + (2.0 * segment) / 3.0;
3618                                         x < stuff_p->c[AE]; x += segment) {
3619                 pr_string(x, y, dash, J_LEFT, (char *) 0, -1);
3620         }
3621         FREE(dash);
3622 }
3623 \f
3624
3625 /* Some characters have upside-down versions that are used
3626  * if stem is down. This table maps such characters to their flips versions.
3627  */
3628
3629 static struct MIRRCHAR {
3630         int     font;           /* Which music font. Note that both the
3631                                  * normal and inverted characters must be
3632                                  * in the same font. (We could relax
3633                                  * this constraint by storing a font for each,
3634                                  * and returning both character and font,
3635                                  * but there's no hardship in this simple way.)
3636                                  */
3637         char    norm;
3638         char    inverted;
3639 } mirrtbl[] = {
3640         { FONT_MUSIC, C_FERM, C_UFERM },
3641         { FONT_MUSIC, C_ACC_HAT, C_ACC_UHAT },
3642         { FONT_MUSIC, C_WEDGE, C_UWEDGE },
3643         { 0, 0 }
3644 };
3645
3646
3647 /* Given a string and the first character in it, if it is a music symbol
3648  * that has a mirrored version, return that, otherwise, return
3649  * it as it was.
3650  */
3651
3652 static int
3653 mirror(str, ch, font)
3654
3655 char *str;      /* the string to check */
3656 int ch;         /* the first character (which better be a music character) */
3657 int font;       /* FONT_MUSIC or some other music font */
3658
3659 {
3660         int i;
3661
3662         for (i = 0; mirrtbl[i].norm != '\0'; i++) {
3663                 if (string_is_sym(str, mirrtbl[i].norm, mirrtbl[i].font) == YES) {
3664                         return((int) mirrtbl[i].inverted);
3665                 }
3666         }
3667         return(ch);
3668 }