2 /* Copyright (c) 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006 by Arkkra Enterprises */
3 /* All rights reserved */
5 /* functions for printing things off of STAFF structs: notes, stems,
6 * rests, flags, beams, etc */
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
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.
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
32 int basictime; /* 8, 16, 32, etc represented by beam */
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,
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,
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,
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));
75 /* print things off of STAFF struct */
80 struct MAINLL *mll_p; /* which main list struct holds the STAFF struct */
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 */
97 debug(512, "pr_staff file=%s lineno=%d staff=%d", mll_p->inputfile,
98 mll_p->inputlineno, mll_p->u.staff_p->staffno);
100 staff_p = mll_p->u.staff_p;
102 if ( svpath(staff_p->staffno, VISIBLE)->visible == NO) {
103 /* invisible staffs are easy to print... */
107 /* do any syllables */
108 for (v = 0; v < staff_p->nsyllists; v++) {
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
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);
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) {
130 if ( grpsyl_p->syl != (char *) 0) {
132 /* if <...> before or after syllable that
133 * were not used for placement, need to
134 * compensate for that */
135 lyr_compensate(grpsyl_p);
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.
145 if ((savedlyr = malloc(strlen(grpsyl_p->syl) + 1))
147 l_no_mem(__FILE__, __LINE__);
149 strcpy(savedlyr, grpsyl_p->syl);
151 /* if syllable ends with a dash or underscore,
152 * they have to be spread between this syllable
154 (void) spread_extender(grpsyl_p, mll_p,
156 staff_p->sylplace[v], YES);
158 /* now print the syllable itself */
159 pr_string(grpsyl_p->c[AW], grpsyl_p->c[AY],
160 grpsyl_p->syl, J_LEFT,
162 grpsyl_p->inputlineno);
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) {
171 grpsyl_p->syl = savedlyr;
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) {
184 t_p = tssv_p = barmll_p->u.bar_p->timedssv_p;
186 /* do notes, etc for each voice on the staff */
187 for (v = 0; v < MAXVOICES; v++) {
189 if (staff_p->groups_p[v] == 0) {
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);
199 /* Set up to handle mid-measure changes, if any */
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) {
211 /* Apply any timed SSVs */
212 while (t_p != 0 && LE(t_p->time_off, now) ) {
216 now = radd(now, grpsyl_p->fulltime);
218 if (grpsyl_p->clef != NOCLEF) {
221 clefsize = (3 * DFLT_SIZE) / 4;
222 widthclef = width(FONT_MUSIC, clefsize,
223 clefchar(grpsyl_p->clef));
224 pr_clef(grpsyl_p->staffno,
226 (widthclef + CLEFPAD) * Staffscale,
229 if (grpsyl_p->grpcont == GC_SPACE) {
230 /* very easy to print a space -- do nothing! */
234 if (grpsyl_p->grpcont == GC_REST) {
235 pr_rest(grpsyl_p, staff_p);
239 if (is_mrpt(grpsyl_p) == YES) {
240 pr_mrpt(grpsyl_p, staff_p);
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
255 else if (grpsyl_p->stemto == CS_BELOW) {
256 for (otherstaff = grpsyl_p->staffno + 1;
257 otherstaff <= Score.staffs;
259 if (svpath(otherstaff, VISIBLE)->visible
266 otherstaff = grpsyl_p->staffno;
268 if (otherstaff < 1 || otherstaff > Score.staffs) {
269 pfatal("failed to find other score for cross-staff stems for leger lines");
272 /* do each note in the group */
273 for (n = 0; n < grpsyl_p->nnotes; n++) {
275 size = (grpsyl_p->notelist[n].notesize ==
276 GS_NORMAL ? DFLT_SIZE :
279 /* we're going to need the NOTE info a lot;
281 noteinfo_p = &(grpsyl_p->notelist[n]);
283 /* do the note head */
284 pr_muschar(noteinfo_p->c[AX],
286 noteinfo_p->headchar,
288 noteinfo_p->headfont);
290 /* do any accidental */
291 pr_accidental(noteinfo_p, grpsyl_p);
294 pr_note_dots(noteinfo_p, grpsyl_p->dots,
296 (double) grpsyl_p->c[AX],
297 (double) grpsyl_p->c[AY]);
299 /* print parentheses around note if any*/
300 if (noteinfo_p->note_has_paren == YES) {
301 pr_parens(noteinfo_p, grpsyl_p);
304 /* print small curve for 1/4 bends */
305 if (noteinfo_p->smallbend == YES) {
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
316 adjust = 2.0 * STEPSIZE;
322 noteinfo_p->c[AE] + adjust,
324 noteinfo_p->c[AY] + 0.5 * STEPSIZE);
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,
335 /* notes are on a different staff */
336 pr_leger(noteinfo_p, grpsyl_p,
341 /* do "with" lists */
342 pr_withlist(grpsyl_p);
344 /* do stems, flags, slash, and alt */
348 if (gets_roll(grpsyl_p, staff_p, v) == YES) {
349 print_roll(grpsyl_p);
353 /* assign anything that happened after start of last group */
359 /* print tuplet numbers if any */
360 pr_tupnums(staff_p->groups_p[v], staff_p);
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);
368 /* now do any associated STUFFs */
369 pr_stuff(staff_p->stuff_p, staff_p->staffno, mll_p);
373 /* if two syllables are to be joined, draw a little curved line between them */
376 do_syl_joins (syl, west, y)
378 char *syl; /* syllable string */
379 double west; /* where syllable was printed */
380 double y; /* where syllable was printed */
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 ' ' */
393 /* skip past any <...> */
396 for (p = syl + 2; *p != '\0'; p++) {
397 switch ( (unsigned) *p & 0xff) {
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
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;
437 do_linetype(L_NORMAL);
439 do_curveto(x + xinc, y - yinc,
440 east - xinc, y - yinc, east, y);
450 /* print things in STUFF list */
453 pr_stuff (stufflist_p, staffno, mll_p)
455 struct STUFF *stufflist_p; /* which list of STUFF */
456 int staffno; /* which staff the stuff is for */
457 struct MAINLL *mll_p;
460 char lch; /* last character in string */
463 /* do each item in stuff list */
464 for ( ; stufflist_p != (struct STUFF *) 0;
465 stufflist_p = stufflist_p->next) {
467 set_staffscale( (stufflist_p->all == YES) ? 0 : staffno);
469 switch (stufflist_p->stuff_type) {
477 /* do 'til' clause if any */
480 /* if special case of ending in ~ or _, don't print the
482 if ((lch = last_char(stufflist_p->string)) == '~' ||
484 stufflist_p->string[strlen(stufflist_p->string)
488 /* print the string at specified place */
489 if (stufflist_p->string != (char *) 0) {
492 /* print grid if appropriate,
493 * otherwise just the string. */
494 if (stufflist_p->modifier != TM_CHORD ||
495 svpath(staffno, GRIDSWHEREUSED)
496 ->gridswhereused == NO ||
498 (stufflist_p->all == YES ?
501 pr_string (stufflist_p->c[AW],
503 stufflist_p->string, J_LEFT,
504 stufflist_p->inputfile,
505 stufflist_p->inputlineno);
513 pr_cresc(stufflist_p);
517 pr_ped_char(stufflist_p, staffno);
521 pr_phrase(stufflist_p->crvlist_p, stufflist_p->modifier,
522 (stufflist_p->modifier == L_NORMAL ? YES : NO),
527 pr_tieslur(stufflist_p, mll_p, staffno);
531 pr_bend(stufflist_p->crvlist_p);
535 pr_tabslur(stufflist_p->crvlist_p,
536 get_ts_style(stufflist_p, mll_p));
543 pfatal("unknown stuff type");
550 /* Print a guitar grid. Return YES if grid was found and printed, else NO. */
553 pr_grid(stuff_p, staffnum)
555 struct STUFF *stuff_p;
564 if ((grid_p = findgrid(stuff_p->string)) == 0) {
565 /* placement phase should have printed a warning already */
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);
574 space = gridspace(staffnum);
575 gridsize(grid_p, staffnum, &north, &south, (float *) 0, (float *) 0);
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);
584 /* print ties and slurs */
587 pr_tieslur(stuff_p, mll_p, staffno)
589 struct STUFF *stuff_p;
590 struct MAINLL *mll_p;
594 int ts_style; /* tie/slur style (L_DOTTED or L_DASHED) */
597 ts_style = get_ts_style(stuff_p, mll_p);
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);
607 /* print a regular tie/slur curve */
608 pr_phrase(stuff_p->crvlist_p, ts_style,
609 (ts_style == L_NORMAL ? YES : NO), staffno );
613 /* given a TIESLUR STUFF, return the line type to use for it */
616 get_ts_style(stuff_p, mll_p)
618 struct STUFF *stuff_p;
619 struct MAINLL *mll_p;
622 struct GRPSYL *prevgrp_p; /* for carryins */
623 int n; /* notelist index */
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
638 for (n = 0; n < prevgrp_p->nnotes; n++) {
640 if (prevgrp_p->notelist[n].nslurto
641 <= stuff_p->curveno) {
642 /* couldn't have come from this grp */
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) {
653 return (prevgrp_p->notelist[n].
654 slurtolist[stuff_p->curveno]
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);
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);
680 /* a non-carried-in tie, use tiestyle */
681 return(stuff_p->begnote_p->tiestyle);
685 /* if none of those cases applied, use normal */
690 /* print a rest symbol */
693 pr_rest(gs_p, staff_p)
695 struct GRPSYL *gs_p; /* information about the rest to be printed */
696 struct STAFF *staff_p;
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 */
706 if (gs_p->basictime < -1) {
707 /* multirest are a special case */
708 pr_multirest(gs_p, staff_p);
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) {
721 if (svpath(staff_p->staffno, STAFFLINES)->stafflines > 1) {
722 halfst = halfstaffhi(staff_p->staffno);
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.
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);
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);
743 pr_muschar(gs_p->c[AX], gs_p->c[AY], muschar, size, FONT_MUSIC);
746 /* get ready to print any dots */
747 adjust = width(FONT_MUSIC, adj_size(size, Staffscale, (char *) 0,
749 y = _Cur[AY] + Stepsize;
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,
761 /* print a measure repeat */
764 pr_mrpt(gs_p, staff_p)
767 struct STAFF *staff_p;
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 */
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);
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);
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. */
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);
810 /* print the dots for dotted notes */
813 pr_note_dots(noteinfo_p, numdots, xdotr, group_x, group_y)
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 */
819 double group_y; /* coord of group, dots are relative to this */
822 float adjust; /* to place dots with proper spacing */
825 /* if note isn't dotted, nothing to do */
830 adjust = width(FONT_MUSIC, adj_size(DFLT_SIZE, Staffscale,
831 (char *) 0, -1), C_DOT) / 2.0;
833 /* go to where first dot belongs */
834 set_cur(group_x + xdotr - adjust, group_y + noteinfo_p->ydotr);
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);
844 /* print parentheses around a note. Should only be called if note_has_paren
848 pr_parens(note_p, gs_p)
851 struct GRPSYL * gs_p;
854 char paren_string[4];
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));
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));
867 /* print the left parenthesis */
868 pr_string(gs_p->c[AX] + note_p->wlparen, y,
869 paren_string, J_LEFT, (char *) 0, -1);
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);
878 /* print "with" lists */
883 struct GRPSYL *gs_p; /* GRPSYL that might have with lists */
886 float y; /* where to start from */
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 */
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 */
908 if (gs_p->nnotes == 0) {
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];
920 y = gs_p->notelist[0].c[AN];
921 x = gs_p->notelist[0].c[AX];
926 /* with goes on opposite side than normal */
927 y = find_y_stem(gs_p);
928 if (gs_p->stemdir == DOWN) {
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];
935 /* beamed notes stems effective stick out a little
936 * farther, so compensate for that */
937 if (gs_p->beamloc != NOITEM) {
943 if (gs_p->stemlen <= 0.0) {
944 y = gs_p->notelist[0].c[AN];
946 if (gs_p->beamloc != NOITEM) {
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);
970 minwithheight = MINWITHHEIGHT * Staffscale;
972 /* do each item in with list */
973 for (index = 0; index < gs_p->nwith; index++) {
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);
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;
989 x_offset = left_width( &(gs_p->withlist[index][0]) );
991 /* get height of item to print */
992 item_height = strheight(gs_p->withlist[index]);
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;
1004 /* no reason to adjust further for 1-line staffs */
1005 if ((stafflines = svpath(gs_p->staffno,
1006 STAFFLINES)->stafflines) > 1) {
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);
1013 /* find y of middle of staff */
1014 ystaff = gs_p->notelist[0].c[AY]
1015 - (gs_p->notelist[0].stepsup
1016 * adjusted_stepsize);
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
1028 pad = (minwithheight - item_height) / 4.0;
1029 top = yposition + (item_height / 2.0) + pad;
1030 bot = yposition - (item_height / 2.0) - pad;
1032 /* check each staff line for collisions, from
1034 for (sl = -(stafflines - 1);
1035 sl <= (stafflines - 1);
1038 /* find y of current staff line */
1039 yline = ystaff + (sl * adjusted_stepsize);
1041 /* check if current staff line goes
1043 * as currently placed */
1044 if (yline < top && yline > bot) {
1045 /* collides--need to move */
1051 yposition += 2.0 * pad;
1052 /* if overdid the move,
1053 * move back a bit */
1054 if (yposition - yline -
1056 > 0.7 * adjusted_stepsize) {
1058 0.4 * adjusted_stepsize;
1062 /* move down to area
1064 yposition -= 2.0 * pad;
1065 if (yline - yposition -
1067 > 0.7 * adjusted_stepsize) {
1069 0.4 * adjusted_stepsize;
1073 /* only 1 staff line can
1074 * possibly interfere,
1075 * and we've found that one, so
1076 * can jump out of loop */
1082 /* adjust y_offset to include the area taken by item */
1083 y_offset += minwithheight * sign;
1085 /* up to now, we've been using the center of the item,
1086 * so now adjust to baseline */
1088 yposition += (item_height / 2.0)
1089 - strascent(gs_p->withlist[index]);
1092 yposition -= (item_height / 2.0)
1093 - strdescent(gs_p->withlist[index]);
1097 /* not too short, handle normally */
1098 y_offset += item_height * sign;
1099 yposition = y + y_offset;
1101 /* adjust to get to baseline of string from top or
1102 * bottom that we've used up to this point */
1104 yposition -= strascent(gs_p->withlist[index]);
1107 yposition += strdescent(gs_p->withlist[index]);
1111 pr_string(x - x_offset, yposition, gs_p->withlist[index],
1112 J_CENTER, gs_p->inputfile, gs_p->inputlineno);
1117 /* print note stems and flags. Also print any slashes and alt lines */
1122 struct GRPSYL *grpsyl_p; /* which group's stem to print */
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
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;
1139 /* if no stem, nothing to do */
1140 if ( grpsyl_p->stemlen <= 0 && grpsyl_p->slash_alt == 0) {
1144 /* figure out x coordinate of stem */
1145 x = find_x_stem(grpsyl_p);
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]);
1151 y2 = find_y_stem(grpsyl_p);
1155 note_p = &(grpsyl_p->notelist [0]);
1157 y2 = find_y_stem(grpsyl_p);
1161 if (note_p->headchar != 0) {
1162 y1 += stem_yoff(note_p->headchar, note_p->headfont,
1164 * (note_p->notesize == GS_NORMAL
1165 ? Stepsize : Stepsize * SM_FACTOR);
1168 if (grpsyl_p->basictime >= 2) {
1169 /* print the stem */
1170 do_linetype(L_NORMAL);
1172 draw_line(x, y1, x, y2);
1174 /* attach any flags as appropriate */
1175 pr_flags(grpsyl_p, (double) x, (double) y2);
1178 /* print any slashes */
1179 if (grpsyl_p->slash_alt > 0) {
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)
1186 if (grpsyl_p->beamloc == NOITEM) {
1187 if (grpsyl_p->grpsize == GS_NORMAL) {
1188 offset += 8.0 * Stdpad;
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;
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)
1208 y_tilt = 2.2 * Stdpad;
1213 /* beamed. Need to slant slashes the same as beam */
1215 grpsize = grpsyl_p->grpsize;
1216 grpvalue = grpsyl_p->grpvalue;
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) {
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) {
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);
1245 /* draw the slashes */
1246 pr_slashes(grpsyl_p, (double) x, (double) y2, (double) sign,
1247 (double) offset, (double) y_tilt);
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;
1257 if (grpsyl_p->next == (struct GRPSYL *) 0) {
1258 pfatal("missing second group in alt pair");
1261 /* figure out how wide to draw the lines and how far apart
1263 if (grpsyl_p->grpsize == GS_NORMAL) {
1264 halfwidth = W_WIDE * Staffscale / PPI / 2.0;
1265 spacing = 5.0 * Stdpad;
1268 halfwidth = W_MEDIUM * Staffscale / PPI / 2.0;
1269 spacing = 3.0 * Stdpad;
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);
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);
1295 grp2y_offset = grp2y - y2;
1299 /* draw the alt lines */
1300 for (slash = -(grpsyl_p->slash_alt) - 1; slash >= 0; slash--) {
1301 y_offset = sign * slash * spacing + (sign * offset);
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
1307 do_line(grp2x, y2 + y_offset + grp2y_offset
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;
1323 pr_slashes(grpsyl_p, x, y, sign, offset, y_tilt)
1325 struct GRPSYL *grpsyl_p;
1340 /* get length based on note head size */
1341 xlen = slash_xlen(grpsyl_p);
1343 /* figure out how wide to make the slashes and how far apart
1345 if (grpsyl_p->grpsize == GS_NORMAL) {
1346 halfwidth = W_WIDE * Staffscale / PPI / 2.0;
1347 spacing = 5 * Stdpad;
1350 halfwidth = W_MEDIUM * Staffscale / PPI / 2.0;
1351 spacing = 4 * Stdpad;
1354 for (slash = grpsyl_p->slash_alt; slash > 0; slash--) {
1355 y_offset = y + sign * (offset + (spacing * slash));
1357 /* draw filled parallelogram */
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);
1369 slash_xlen(grpsyl_p)
1371 struct GRPSYL *grpsyl_p;
1374 return (SLASHHORZ * Stepsize *
1375 (grpsyl_p->grpsize == GS_NORMAL ? 1.0 : SM_FACTOR));
1379 /* print flags on 8th and shorter notes */
1382 pr_flags(grpsyl_p, x, y)
1384 struct GRPSYL *grpsyl_p; /* group for which to draw flags */
1386 double y; /* coord of end of stem */
1389 int muschar; /* what kind of flag to print */
1390 float y_offset; /* from end of stem */
1391 int f; /* how many flags */
1395 /* only 8th and shorter notes might have flags */
1396 if (grpsyl_p->basictime < 8) {
1400 /* if not a note, no flag */
1401 if (grpsyl_p->grpcont != GC_NOTES) {
1405 /* if beamed, no flag */
1406 if (grpsyl_p->beamloc != NOITEM) {
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);
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--) {
1421 y_offset = f * (grpsyl_p->grpsize == GS_NORMAL ?
1422 FLAGSEP : SMFLAGSEP);
1425 y_offset = -f * (grpsyl_p->grpsize == GS_NORMAL ?
1426 FLAGSEP : SMFLAGSEP);
1429 pfatal("bad flag type");
1431 return; /* to shut up compiler warning about unused */
1434 y_offset *= Staffscale;
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),
1440 y + y_offset, muschar, size, FONT_MUSIC);
1445 /* print any accidental */
1448 pr_accidental(noteinfo_p, grpsyl_p)
1450 struct NOTE *noteinfo_p; /* info about the note being printed */
1451 struct GRPSYL *grpsyl_p; /* info about the group conatining the note */
1454 int muschar; /* which accidental symbol to draw */
1456 int a_size; /* size adjusted for Staffscale */
1459 /* figure out which accidental symbol to use */
1460 muschar = acc2char(noteinfo_p->accidental);
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);
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 ( ) */
1478 /* create string for "(" */
1479 (void) sprintf(paren_string, "%c%c%c",
1480 FONT_TR, a_size, '(');
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);
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);
1495 pr_muschar(_Cur[AX] +
1496 width(FONT_MUSIC, a_size, muschar) / 2.0,
1497 noteinfo_p->c[AY], muschar, size,
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);
1511 /* print appropriate number of leger lines */
1514 pr_leger(noteinfo_p, gs_p, staffno)
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 */
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 */
1529 if ((lines2draw = numlegers(noteinfo_p)) < 1) {
1530 /* No legers needed for this note */
1534 /* Is note above or below the middle of the staff? */
1535 sign = noteinfo_p->stepsup > 0.0 ? 1.0 : -1.0;
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;
1547 /* Draw the legers */
1548 do_linetype(L_NORMAL);
1549 is_intermediate = NO;
1550 for ( ; lines2draw > 0; lines2draw--) {
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));
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.
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);
1569 draw_line( noteinfo_p->c[AW] - left_leger, y,
1570 noteinfo_p->c[AE] + right_leger, y);
1571 is_intermediate = YES;
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) {
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. */
1587 numlegers(noteinfo_p)
1589 struct NOTE *noteinfo_p;
1592 return (abs(noteinfo_p->stepsup) / 2) - 2;
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.
1606 leger_length(noteinfo_p, othergs_p, lines, other_is_prev, is_intermediate)
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 */
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 */
1621 if (othergs_p == 0) {
1622 /* No group to collide with */
1625 if (othergs_p->grpcont != GC_NOTES) {
1626 /* Can't have leger lines */
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.
1633 adjust = (is_intermediate ? 0.5 * Stdpad : 0.0);
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 */
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. */
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
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];
1661 distance = othergs_p->notelist[n].c[AW] - noteinfo_p->c[AE];
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.
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;
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 */
1690 tupnumsize(gs_p, west_p, east_p, height_p, staff_p)
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 */
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 */
1707 /* assume all cue till proven otherwise */
1710 /* find x of middle of tuplet number */
1711 if (gs_p->tuploc == LONEITEM) {
1712 if (gs_p->grpsize != GS_SMALL) {
1715 num_x = gs_p->c[AX];
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) {
1723 if (last_gs_p->tuploc == ENDITEM) {
1727 if (last_gs_p == (struct GRPSYL *) 0) {
1728 pfatal("missing end tuplet in tupnumsize");
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.
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;
1745 num_x = (last_gs_p->c[AX] + gs_p->c[AX]) / 2.0;
1749 /* prepare the string to print */
1750 numstr = num2str(gs_p->tupcont);
1751 /* force to 11-point newcentury bold-italics, unless all cue,
1753 numstr[0] = FONT_NX;
1754 numstr[1] = (char) adj_size((all_cue == YES ? 9 : 11), Staffscale,
1756 halfnumwidth = strwidth(numstr) / 2.0;
1758 /* return the values */
1759 *west_p = num_x - halfnumwidth - Stdpad;
1760 *east_p = num_x + halfnumwidth + Stdpad;
1761 *height_p = strheight(numstr);
1766 /* go through measure. If there are any tuplets, print a number by them,
1767 * along with bracket if appropriate. */
1770 pr_tupnums(gs_p, staff_p)
1772 struct GRPSYL *gs_p; /* start from here to walk through list of groups */
1773 struct STAFF *staff_p; /* staff pointing to gs_p */
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) */
1797 /* go through all the groups */
1798 for ( ; gs_p != (struct GRPSYL *) 0; gs_p = gs_p->next) {
1800 switch (gs_p->tuploc) {
1806 /* remember beginning for later use */
1822 /* if not to be printed, nothing to do except reinit */
1823 if (gs_p->printtup == PT_NEITHER) {
1828 /* we don't do tuplet numbers on cross-staff beams--
1829 * it's virtually impossible to know where to put them
1831 if (gs_p->beamto != CS_SAME) {
1836 /* If the tuplet is all spaces,
1837 * there is nothing to draw a bracket over,
1838 * and trying to do so causes problems,
1840 for (g_p = first_gs_p; g_p->tuploc != NOITEM;
1842 if (g_p->grpcont != GC_SPACE) {
1843 /* good--it has something
1844 * other than spaces */
1848 if (g_p->tuploc == ENDITEM
1849 || g_p->tuploc == LONEITEM) {
1850 /* reached end of all-space tuplet */
1854 if (g_p->grpcont == GC_SPACE) {
1855 /* must have been all spaces */
1860 /* if tuplet doesn't match beaming, need bracket */
1861 need_brack = tupgetsbrack(first_gs_p);
1863 if (num_notes == 0) {
1864 pfatal("no notes in tuplet");
1867 numstr = tupnumsize(first_gs_p, &numwest, &numeast,
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;
1878 y1 = first_gs_p->c[AS];
1880 brackdir = 3.0 * Stdpad;
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);
1890 /* add tuplet bracket if necessary */
1891 if (need_brack == YES) {
1892 do_linetype(L_NORMAL);
1894 /* adjust to reach edge of note head */
1895 size = (first_gs_p->grpsize == GS_NORMAL ?
1896 DFLT_SIZE : SMALLSIZE)
1898 if (first_gs_p->grpcont == GC_NOTES) {
1899 x_adjust = widest_head(first_gs_p)
1902 else if (first_gs_p->grpcont == GC_REST) {
1903 x_adjust = width(FONT_MUSIC, size,
1905 restchar(first_gs_p->basictime))
1911 x1 = first_gs_p->c[AX] - x_adjust;
1913 size = (gs_p->grpsize == GS_NORMAL ?
1914 DFLT_SIZE : SMALLSIZE)
1916 if (gs_p->grpcont == GC_NOTES) {
1917 x_adjust = widest_head(gs_p)
1920 else if (gs_p->grpcont == GC_REST) {
1921 x_adjust = width(FONT_MUSIC, size,
1922 restchar(gs_p->basictime))
1928 x2 = gs_p->c[AX] + x_adjust;
1930 /* move the bracket line up from the baseline
1932 y1 += (4.0 * Stdpad);
1933 y2 += (4.0 * Stdpad);
1934 num_y += (4.0 * Stdpad);
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 */
1944 y_adjust = (((numeast - numwest
1946 (num_y - y1)) / (numeast - x1))
1950 draw_line(x1, y1, numwest - Stdpad,
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);
1958 /* re-init in case other tuplets in same measure */
1964 pfatal("bad tuplet type");
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 */
1978 struct GRPSYL *gs_p; /* first group of tuplet */
1981 /* If nothing is to be printed or number only, no bracket */
1982 if (gs_p->printtup == PT_NEITHER || gs_p->printtup == PT_NUMBER) {
1986 /* single chord tuplets never get a bracket -- not enough room
1988 if (gs_p->tuploc == LONEITEM) {
1992 /* if user insists on a bracket, we oblige */
1993 if (gs_p->printtup == PT_BOTH) {
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) {
2004 if (gs_p->tuploc != gs_p->beamloc) {
2007 if (gs_p->tuploc == ENDITEM) {
2008 /* matched beam everywhere, so no bracket needed */
2012 pfatal("missing end tuplet");
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 */
2026 tupdir(gs_p, staff_p)
2028 struct GRPSYL *gs_p; /* group in tuplet */
2029 struct STAFF *staff_p; /* staff pointing to gs_p */
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 */
2041 smalltime.d = 2 * MAXBASICTIME;
2044 switch (gs_p->tuploc) {
2048 /* this is the one we want */
2052 pfatal("arg of tupdir is not in a tuplet");
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) {
2062 if (gs_p == (struct GRPSYL *) 0) {
2063 pfatal("can't find beginning of tuplet");
2068 /* figure out which side. First determine vscheme */
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.
2078 if (staff_p->groups_p[1] == (struct GRPSYL *) 0) {
2079 return(tupdir1voice(gs_p));
2082 /* voice 3 pays no attention to any other voices. */
2083 if (gs_p->vno == 3) {
2084 return(tupdir1voice(gs_p));
2087 if ((vscheme = svpath(staff_p->staffno, VSCHEME)->vscheme) == V_1) {
2088 return(tupdir1voice(gs_p));
2090 else if (vscheme == V_2OPSTEM) {
2091 /* 2 opposing stem voices, always put tuplet above voice 1 and
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;
2100 return(gs_p->vno == 1 ? PL_ABOVE : PL_BELOW);
2103 /* find the time period taken by tuplet */
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);
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);
2118 /* add on a little bit for the final group of the tuplet */
2119 endtime = radd(endtime, smalltime);
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)
2125 /* other voice is space: treat like V_1 */
2126 return(tupdir1voice(save_gs_p));
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;
2137 return(gs_p->vno == 1 ? PL_ABOVE : PL_BELOW);
2143 /* return PL_ABOVE or PL_BELOW for tup location assuming a single voice */
2148 struct GRPSYL *gs_p; /* first group of tuplet */
2151 int stemdirsum; /* sum of stem directions to see if mostly up or down */
2154 /* if user specified a direction, the answer is easy */
2155 if (gs_p->tupside != PL_UNKNOWN) {
2156 return(gs_p->tupside);
2159 /* Count up stem directions. Whichever side
2160 * has more stems, put it on that side. In case of tie,
2161 * arbitrarily choose above. */
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);
2167 if (gs_p->tuploc == LONEITEM || gs_p->tuploc == ENDITEM) {
2172 return(stemdirsum >= 0 ? PL_ABOVE : PL_BELOW);
2176 /* go through measure, printing any beams. Gets called once for normal sized
2177 * notes, once for cue notes, and once for grace note. */
2180 pr_beams(gs_p, grpvalue, grpsize)
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 */
2188 struct GRPSYL *startbeam_p; /* first in beam group */
2189 int t; /* 8, 16, etc for basictimes */
2192 /* go through all the grpsyls in measure */
2193 for ( ; gs_p != (struct GRPSYL *) 0; gs_p = gs_p->next) {
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) {
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) {
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) {
2217 pfatal("pr_beams couldn't find end of beam group");
2220 /* now go through beam group drawing beams for 8th notes,
2222 for (t = 8; t <= MAXBASICTIME; t <<= 1) {
2223 if (draw_beams(startbeam_p, gs_p, t, grpsize, grpvalue)
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.
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:
2248 * (32nd) X --> X . . .
2250 * (16th) X --> X --> X . X --> X (32nd)
2252 * return_value --> X --> X --> X --> X --> X --> X --> X --> X (8th)
2254 * . . X --> X --> X (16th)
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.
2267 static struct CSBINFO *
2268 mkcsbmesh(begin_p, end_p)
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
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, ...) */
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;
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);
2299 /* set horizontal list links */
2300 if (csbi_list_p == 0) {
2301 /* first item on the horizontal list */
2302 csbi_list_p = csbi_p;
2305 /* link from previous horizontally */
2306 prevcsbi_p->next = csbi_p;
2308 prevcsbi_p = csbi_p;
2311 /* init vertical list links */
2312 csbi_p->above_p = csbi_p->below_p = 0;
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;
2319 /* remember the shortest basictime anywhere in the beam */
2320 if (gs_p->basictime > shortest) {
2321 shortest = gs_p->basictime;
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.
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 */
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.
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) {
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);
2353 csbi_p->basictime = basictime;
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;
2363 stemdir = gs_p->stemdir;
2365 /* Prepare to link more on horizonally,
2366 * if beam goes further. */
2367 prevcsbi_p = csbi_p;
2369 /* set vertical links */
2370 if (stemdir == DOWN) {
2371 /* Must be from staff above.
2372 * Find current top, and add
2374 for (c_p = csbi8_p; c_p->above_p != 0;
2375 c_p = c_p->above_p) {
2378 c_p->above_p = csbi_p;
2379 csbi_p->below_p = c_p;
2380 csbi_p->above_p = 0;
2383 /* similar for from staff below */
2384 for (c_p = csbi8_p; c_p->below_p != 0;
2385 c_p = c_p->below_p) {
2388 c_p->below_p = csbi_p;
2389 csbi_p->above_p = c_p;
2390 csbi_p->below_p = 0;
2394 /* If we were doing a beam before,
2400 return(csbi_list_p);
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) */
2411 draw_beams(gs_p, endbeam_p, basictime, grpsize, grpvalue)
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 */
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
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 */
2437 double stemdist; /* distance between stems */
2438 double pbeam_len; /* length of partial beam */
2441 /* get relevant group, accounting for cross-staff beams */
2443 gs_p = neighboring_note_beam_group(gs_p, first_p, NO);
2445 /* go through the list */
2446 while ( gs_p != endbeam_p->next) {
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)) {
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 ) {
2461 /* if not beamed, skip */
2462 if ( gs_p->beamloc == NOITEM) {
2463 pfatal("non-beam inside beam group\n");
2466 /* if this one deserves another beam,
2467 * keep track of that. If not, break out */
2468 if (gs_p->basictime >= basictime) {
2475 if (gs_p->breakbeam == YES && basictime > 8) {
2484 /* prepare to do next one */
2485 if (gs_p != endbeam_p->next) {
2486 gs_p = nxtbmgrp(gs_p, first_p, endbeam_p->next);
2489 /* if none we looked at deserved a beam, keep looking */
2490 if (end_p == (struct GRPSYL *) 0) {
2494 /* calculate where on stem the beam should start */
2495 y_offset = beam_offset(numbeams(basictime),
2496 begin_p->grpsize, begin_p->stemdir);
2498 if (end_p->grpsize == GS_NORMAL) {
2499 halfwidth = W_WIDE * Staffscale / PPI / 2.0;
2500 halfstem = W_NORMAL * Staffscale / PPI / 2.0;
2503 halfwidth = W_WIDE * Staffscale * SM_FACTOR / PPI / 2.0;
2504 halfstem = W_NORMAL * Staffscale * SM_FACTOR / PPI / 2.0;
2507 /* check if single group.
2508 * If so, need to do a partial beam, otherwise full beam */
2510 /* rests and spaces don't get beams,
2511 * so don't get partial ones */
2512 if (end_p->grpcont != GC_NOTES) {
2516 side = pbeamside(end_p, first_p);
2518 /* Now that we decided where the
2519 * partial beam goes, we can draw it */
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);
2531 other_p = nxtbmgrp(end_p, first_p, end_p->next);
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
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);
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);
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);
2562 /* adjust to overlap stem */
2563 x_begin += halfstem * side;
2565 /* determine partial beam length */
2566 /* find distance between stems */
2567 if (x_begin < x_other) {
2568 stemdist = x_other - x_begin;
2571 stemdist = x_begin - x_other;
2573 /* if wide enough, use note head width, else less */
2574 if (stemdist < 5.0 * Stepsize) {
2575 pbeam_len = 0.4 * stemdist;
2578 pbeam_len = widest_head(end_p) * Staffscale;
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);
2589 /* draw a normal beam */
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.
2596 if (begin_p->beamto == CS_SAME) {
2597 end_y_offset = y_offset;
2600 end_y_offset = end_bm_offset(first_p, end_p,
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.
2610 if (begin_p->stemlen <= 0.0 && end_p->stemlen <= 0.0) {
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,
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.
2635 end_bm_offset(top_first_p, end_p, basictime)
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. */
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 */
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;
2668 nextvert_p = c_p->above_p;
2671 for (c_p = csbi_p->below_p; c_p != 0;
2673 nextvert_p = c_p->below_p;
2676 nexthor_p = csbi_p->next;
2680 /* Calculate everything for current beam */
2681 csbi_list_p = mkcsbmesh(top_first_p, end_p);
2682 cached_gs_p = top_first_p;
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) {
2692 pfatal("couldn't find beam end group in end_bm_offset()");
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.
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.
2703 for (c_p = csbi_p; c_p->below_p != 0; c_p = c_p->below_p) {
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) {
2712 pfatal("failed to find cross staff beam info go up");
2716 /* similar for staff below groups */
2717 for (c_p = csbi_p; c_p->above_p != 0; c_p = c_p->above_p) {
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) {
2726 pfatal("failed to find cross staff beam info go up");
2729 return (beam_offset(nbeams, end_p->grpsize, end_p->stemdir));
2733 /* find y offset on stem based on number of beams, whether normal or small
2734 * notes, and stem direction */
2737 beam_offset(nbeams, gsize, stemdir)
2739 int nbeams; /* how many beams */
2740 int gsize; /* GS_NORMAL or GS_SMALL */
2741 int stemdir; /* UP or DOWN */
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)
2750 * (stemdir == UP ? -POINT : POINT) );
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 */
2759 nxtbmgrp(gs_p, first_p, endnext_p)
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
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
2773 int grpsize, grpvalue;
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.
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. */
2782 if ((gs_p = gs_p->gs_p) == (struct GRPSYL *) 0) {
2783 pfatal("can't find matching beam chord");
2786 /* skip any lyrics and such till we find the beamed-to group */
2787 } while (gs_p->beamto != CS_ABOVE);
2790 /* need to skip past any groups of the wrong kind */
2791 grpsize = first_p->grpsize;
2792 grpvalue = first_p->grpvalue;
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) {
2799 } while (gs_p->grpsize != grpsize || gs_p->grpvalue != grpvalue);
2801 /* if past end of beam group, report that we're done */
2802 if (gs_p->beamloc != INITEM && gs_p->beamloc != ENDITEM) {
2806 return(neighboring_note_beam_group(gs_p, first_p, NO));
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 */
2816 prevbmgrp(gs_p, first_p)
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
2823 int grpsize, grpvalue;
2826 staffno = gs_p->staffno;
2828 /* need to skip past any groups of the wrong kind */
2829 grpsize = first_p->grpsize;
2830 grpvalue = first_p->grpvalue;
2832 /* Move to prev group. */
2833 if ((gs_p = gs_p->prev) == (struct GRPSYL *) 0) {
2834 pfatal("prevbmgrp couldn't find prev group");
2836 } while (gs_p->grpsize != grpsize || gs_p->grpvalue != grpvalue);
2838 gs_p = neighboring_note_beam_group(gs_p, first_p, YES);
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) {
2851 /* now take the group right before the space */
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 */
2863 static struct GRPSYL *
2864 neighboring_note_beam_group(gs_p, first_p, backwards)
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
2869 int backwards; /* if YES, go backwards (find the previous
2870 * group rather than the following) */
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 */
2878 /* skip over any embedded rests--they are not notes. */
2879 while (gs_p->grpcont == GC_REST) {
2880 if (backwards == YES) {
2888 pfatal("neighboring_note_beam_group didn't find note group");
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) {
2897 if (backwards == YES) {
2902 } while (gs_p != 0 && gs_p->grpcont != GC_NOTES);
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 */
2910 if ((gs_p = gs_p->gs_p) ==
2911 (struct GRPSYL *) 0) {
2912 pfatal("can't find matching beam chord");
2915 /* skip any lyrics and such till we find the
2916 * group beamed to us */
2917 } while (gs_p->beamto != CS_ABOVE);
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) {
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) {
2935 if (tgs_p == gs_p) {
2936 /* Aha! We found it! */
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. */
2949 pfatal("failed to find group when jumping back to above staff");
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. */
2961 pbeamside(gs_p, first_p)
2963 struct GRPSYL *gs_p;
2964 struct GRPSYL *first_p;
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;
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) {
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
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) {
2999 else if (prevgs_p != 0 && prevgs_p->breakbeam == YES) {
3002 else if (beams2left > beams2right) {
3005 else if (beams2right > beams2left) {
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 */
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
3024 beams2left = prevgs_p->dots;
3025 beams2right = nextgs_p->dots;
3026 if (beams2right > beams2left) {
3036 pfatal("invalid beamloc passed to pbeamside");
3038 return(PB_LEFT); /* to shut up bogus compiler warning */
3045 * Name: chkgroupings()
3047 * Abstract: Decide partial beam side based on groupings of notes.
3049 * Returns: YES if it found an answer (stored in *side_p), NO if not
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.
3061 chkgroupings(side_p, thisgs_p)
3063 int *side_p; /* where to put the answer, if found */
3064 struct GRPSYL *thisgs_p; /* the GRPSYL we are working on */
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 */
3082 * If we're doing grace beams, skip this whole thing, since we're
3083 * dealing with time values, and they are all zero.
3085 if (thisgs_p->grpvalue == GV_ZERO) {
3089 /* find the time offset of thisgs_p by adding up all previous GRPSYLs*/
3091 for (gs_p = thisgs_p->prev; gs_p != 0; gs_p = gs_p->prev) {
3092 thisstart = radd(thisstart, gs_p->fulltime);
3095 /* find offset of GRPSYL following thisgs_p */
3096 nextstart = radd(thisstart, thisgs_p->fulltime);
3099 * Interior notes of tuplets are dealt with in a special way.
3101 if (thisgs_p->tuploc == INITEM) {
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.)
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);
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);
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.
3127 quotient = rdiv(tupstart, tupdur);
3128 if (quotient.d != 1) {
3132 /* the first group length to consider is tupdur/tupcont */
3134 grouplen.d *= thisgs_p->tupcont;
3137 /* loop until an answer is found, or we give up */
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.
3146 if (LE(grouplen, thisgs_p->fulltime)) {
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.
3155 quotient = rdiv(thisstart, grouplen);
3156 if (quotient.d == 1) {
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.
3167 quotient = rdiv(nextstart, grouplen);
3168 if (quotient.d == 1) {
3173 /* divide grouplen by 2 and try again */
3174 grouplen = rdiv(grouplen, Two);
3179 * This is the normal case, not the interior of a tuplet.
3182 /* get all the prime factors of the time sig's numerator */
3183 factors = factor(Score.timenum);
3185 grouplen = Score.time; /* first group is the whole measure */
3186 counts = Score.timenum; /* number of counts in measure */
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.
3195 fraction = YES; /* default to "fraction of a count" */
3197 /* if there are still multiple counts, divide out a prime */
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.
3208 for (n = Score.timenum; n > 4 && factors[n] == 0; n--)
3210 /* if we found a 5 or greater, use it */
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.
3219 } else if (counts % 2 == 0) {
3222 /* no 2s either, so look for 3s */
3223 } else if (counts % 3 == 0) {
3227 /* no factors left, so flag it by setting fact to 1 */
3232 * If a factor was found, divide it out, and remember
3233 * that we are not yet dealing with fractions of a
3242 if (fraction == YES) {
3244 * We are dealing with fractions of a count, so divide
3247 grouplen = rdiv(grouplen, Two);
3250 * Using the number of counts remaining, form the
3251 * length in lowest terms.
3253 grouplen.n = counts;
3254 grouplen.d = Score.timeden;
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.
3264 if (LE(grouplen, thisgs_p->fulltime)) {
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.
3273 quotient = rdiv(thisstart, grouplen);
3274 if (quotient.d == 1) {
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.
3284 quotient = rdiv(nextstart, grouplen);
3285 if (quotient.d == 1) {
3291 return (NO); /* we can never get here; this is for lint */
3295 /* actually draw a beam */
3298 do_beam(x1, y1, x2, y2, halfwidth)
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 */
3307 do_moveto(x1, y1 + halfwidth);
3308 do_line(x2, y2 + halfwidth);
3309 do_line(x2, y2 - halfwidth);
3310 do_line(x1, y1 - halfwidth);
3316 /* print a multirest */
3319 pr_multirest(gs_p, staff_p)
3321 struct GRPSYL *gs_p; /* info about the multirest */
3322 struct STAFF *staff_p;
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 */
3332 /* avoid core dumps */
3333 if (Score_location_p == (float *) 0) {
3334 pfatal("can't do multirest: no feed");
3338 /* determine where to place the multirest */
3339 y = mr_y_loc(gs_p->staffno);
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.
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... */
3359 center = (gs_p->c[AE] + gs_p->c[AW]) / 2.0;
3360 size = (gs_p->grpsize == GS_NORMAL ? DFLT_SIZE : SMALLSIZE);
3362 switch (gs_p->basictime) {
3364 pr_muschar(center, gs_p->c[AY], C_DWHREST, size, FONT_MUSIC);
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);
3371 pr_muschar(center, gs_p->c[AY], C_QWHREST, size, FONT_MUSIC);
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);
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);
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);
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);
3391 pfatal("restsymmult with illegal number of measures (%d)",
3392 -(gs_p->basictime) );
3397 /* draw vertical lines at each end */
3398 do_linetype(L_MEDIUM);
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));
3403 /* draw heavy horizontal */
3404 do_linetype(L_WIDE);
3405 draw_line(west, y, east, y);
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);
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 */
3421 mrnum(staff_p, x_p, y_offset_p, height_p, width_p)
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 */
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 */
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];
3441 if (v == MAXVOICES) {
3442 pfatal("no visible voice found by mrnum");
3444 if (gs_p->grpcont == GC_NOTES) {
3445 /* this is a measure repeat */
3446 numstr = num2str(staff_p->mrptnum);
3447 numstr[0] = FONT_TR;
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;
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);
3462 return (char *) 0; /* to shut up bogus compiler warning */
3464 numstr[1] = (char) adj_size((int) numstr[1], Staffscale, (char *) 0, -1);
3466 *width_p = strwidth(numstr);
3467 *height_p = strheight(numstr);
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;
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. */
3485 int num; /* the number to convert */
3488 static char numstr[12];
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);
3497 /* print cresc or decresc */
3502 struct STUFF *stuff_p; /* info about what to print and where */
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 */
3510 do_linetype(L_NORMAL);
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);
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);
3527 pfatal("pr_cres called for something other than cresc/decresc");
3529 return; /* to shut up bogus compiler warning about unused variables */
3532 /* draw the two sides of the hairpin */
3533 draw_line(x1, line1y1, x2, line1y2);
3534 draw_line(x1, line2y1, x2, line2y2);
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. */
3546 struct STUFF *stuff_p; /* a stuff which may have a til clause */
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 */
3557 if (stuff_p->end.bars <= 0 && stuff_p->end.count <= 0.0) {
3558 /* no til clause, so nothing to do */
3562 /* figure out how much to extend */
3563 extlen = stuff_p->c[AE] - stuff_p->c[AW] - strwidth(stuff_p->string);
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 */
3573 y += (2.0 * Stepsize);
3574 draw_wavy(stuff_p->c[AE] - extlen, y, stuff_p->c[AE], y);
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);
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);
3590 else if (stuff_p->stuff_type == ST_OCTAVE) {
3592 if ( extlen < (4.0 * Stepsize)) {
3593 /* too short to bother */
3597 y += (1.5 * Stepsize);
3598 do_linetype(L_DASHED);
3599 draw_line(stuff_p->c[AE] - extlen + (2.0 * Stepsize), y,
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)));
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);
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);
3625 /* Some characters have upside-down versions that are used
3626 * if stem is down. This table maps such characters to their flips versions.
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.)
3640 { FONT_MUSIC, C_FERM, C_UFERM },
3641 { FONT_MUSIC, C_ACC_HAT, C_ACC_UHAT },
3642 { FONT_MUSIC, C_WEDGE, C_UWEDGE },
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
3653 mirror(str, ch, font)
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 */
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);