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
);