1 /* Copyright (c) 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005 by Arkkra Enterprises */
2 /* All rights reserved */
6 * Description: This file contains functions for setting all remaining
7 * relative vertical coordinates.
15 /* how many rectangles to malloc initially and at each realloc if needed */
16 #define RECTCHUNK (100)
18 /* rectangle structure; see procscore() prologue for explanation of its use */
20 float n
, s
, e
, w
; /* boundaries of a rectangle */
21 /* horz coords are absolute; vertical coords */
22 /* are relative to center staff line */
23 /* (baseline for "between") */
24 short relevant
; /* is rectangle relevant? */
25 short tried
; /* have we tried this one yet? */
27 static struct RECTAB
*rectab
; /* ptr to malloc'ed and realloc'ed array */
29 /* this fudge factor prevents roundoff error from causing overlap */
32 /* these symbols tell certain subroutines which things to work on */
33 #define DO_OTHERS 0 /* default */
37 static int reclim
; /* index after last rectangle in rectab */
39 static void procstaff
P((struct MAINLL
*mainll_p
, int s
));
40 static void dostaff
P((int s
, int place
));
41 static void dogroups
P((struct MAINLL
*start_p
, int s
, int place
));
42 static void llgrps
P((struct STAFF
*staff_p
, struct GRPSYL
*gs_p
, int place
));
43 static void dobeamalt
P((struct MAINLL
*start_p
, int s
, int place
));
44 static void onebeamalt
P((struct GRPSYL
*gs_p
));
45 static double getstemendvert
P((struct GRPSYL
*gs_p
));
46 static void linerects
P((double x1
, double y1
, double x2
, double y2
, int side
,
48 static void docurve
P((struct MAINLL
*start_p
, int s
, int place
,
50 static void curverect
P((int s
, struct STUFF
*stuff_p
, double halfstaff
));
51 static void curvepiecerect
P((double x1
, double y1
, double x2
, double y2
,
53 static void dotuplet
P((struct MAINLL
*start_p
, int s
, int place
));
54 static void onetuplet
P((struct STAFF
*staff_p
, struct GRPSYL
*start_p
,
56 static void domiscstuff
P((struct MAINLL
*start_p
, int s
, int place
,
57 unsigned long do_which
));
58 static void dolyrics
P((struct MAINLL
*start_p
, int s
, int place
));
59 static void getvsize
P((struct MAINLL
*start_p
, int s
, int place
, int v
,
60 float *asc_p
, float *des_p
));
61 static void setsylvert
P((struct MAINLL
*start_p
, int s
, int place
, int v
,
63 static void dopedal
P((struct MAINLL
*start_p
, int s
));
64 static void doendings
P((struct MAINLL
*start_p
, int s
));
65 static void storeend
P((struct MAINLL
*start_p
, struct MAINLL
*end_p
, int s
));
66 static void dorehears
P((struct MAINLL
*start_p
, int s
));
67 static double stackit
P((double west
, double east
, double height
, double dist
,
69 static void inc_reclim
P((void));
74 * Abstract: Set all relative vertical coords not already set.
78 * Description: This function sets all remaining relative vertical coords.
79 * It calls procstaff() once for each staff in each score to
87 struct MAINLL
*mainll_p
; /* point along main linked list */
88 struct MAINLL
*end_p
; /* point at end of a piece of MLL */
89 struct MAINLL
*m2_p
; /* another pointer along MLL */
90 int s
; /* staff number */
91 int gotbar
; /* was a bar found in this chunk? */
96 * Find each section of the main linked list, delimited by FEEDs.
97 * For each such section, call procstaff() for each visible staff.
98 * Keep SSVs up to date so that we always know what staffs are visible.
100 initstructs(); /* clean out old SSV info */
102 /* skip anything before first FEED first */
103 for (mainll_p
= Mainllhc_p
; mainll_p
->str
!= S_FEED
;
104 mainll_p
= mainll_p
->next
) {
105 if (mainll_p
->str
== S_SSV
)
106 asgnssv(mainll_p
->u
.ssv_p
);
110 * Initially allocate RECTCHUNK rectangles. If we find we need more at
111 * some point, we'll realloc to get more.
113 MALLOC(RECTAB
, rectab
, RECTCHUNK
);
117 * Find end of this chunk. If it has no bars in it, this must
118 * either be the end of the MLL and there was a final feed
119 * after all the music data, or else this is a block. Either
120 * way, there is no need to process this chunk.
123 for (end_p
= mainll_p
->next
; end_p
!= 0 &&
124 end_p
->str
!= S_FEED
; end_p
= end_p
->next
) {
125 if (end_p
->str
== S_BAR
)
130 break; /* end of MLL, get out */
132 /* update SSVs to beginning of next score */
133 for (m2_p
= mainll_p
->next
; m2_p
!= end_p
;
135 if (m2_p
->str
== S_SSV
)
136 asgnssv(m2_p
->u
.ssv_p
);
139 mainll_p
= end_p
; /* block, skip by it */
143 for (s
= 1; s
<= Score
.staffs
; s
++) {
144 if (svpath(s
, VISIBLE
)->visible
== YES
)
145 procstaff(mainll_p
, s
);
148 /* update SSVs to beginning of next score */
149 for (m2_p
= mainll_p
->next
; m2_p
!= end_p
; m2_p
= m2_p
->next
) {
150 if (m2_p
->str
== S_SSV
)
151 asgnssv(m2_p
->u
.ssv_p
);
165 * Abstract: Set all relative vertical coords for a staff in one score.
169 * Description: This function sets all remaining relative vertical coords
170 * for a given staff of a given score.
174 procstaff(start_p
, s
)
176 struct MAINLL
*start_p
; /* FEED at the start of this score */
177 int s
; /* the staff we are to work on */
180 struct MAINLL
*mainll_p
;/* point along main linked list */
181 char *order
; /* point at a subarray in markorder */
182 int stk
; /* stacking order number */
183 int mk
; /* mark type */
184 unsigned long do_which
; /* bit map of which mark types to do */
185 float north
, south
; /* relative coords of staff */
186 float hb
; /* height of "between" objects */
187 int k
; /* loop variable */
190 debug(32, "procstaff file=%s line=%d s=%d", start_p
->inputfile
,
191 start_p
->inputlineno
, s
);
193 /* set globals like Staffscale for use by the rest of the file */
197 * Each structure in rectab[] represents something to be drawn that
198 * is associated with this staff, beginning with the staff itself.
199 * The coordinates define the rectangle that surrounds the object.
200 * The rectangles' edges are horizontal and vertical. So if an object
201 * (like a slanted beam) doesn't fit well in such a recangle, multiple
202 * rectangles are used to enclose pieces of it, as in integration in
205 * The first part of this function does this for things that are above
206 * the staff. The second part does it for things that are below it.
207 * The third part does it for items that are to be centered (if
208 * possible) between two staffs. In the first two parts, rectangles
209 * are added to the table one at a time, working outwards from the
210 * staff. In the third part, they are piled on an imaginary baseline.
212 * Some objects (like note groups) already have an assigned position.
213 * and their rectangles are simply added to the table, regardless of
214 * whether they overlap preexisting rectangles.
216 * Some objects (like phrase marks) get their positions figured out
217 * now, by some unique algorithm that doesn't make use of the table of
218 * rectangles, and then their rectangles are added to the table, again
219 * not worrying about overlap with preexisting rectangles.
221 * Some objects (like "stuff" to be printed) make use of the table to
222 * figure out where their rectangles should be placed. They are placed
223 * as close to the staff (or baseline, for "between") as is possible
224 * without overlapping preexisting rectangles (or, in the case of
225 * chords, getting closer to the staff than allowed by "chorddist"; or
226 * in the case of rom, ital, bold, boldital, or rehearsal marks, closer
227 * than "dist"; or in the case of dynamics, closer than "dyndist").
228 * (And some things have their own "dist" to override these parameters,
229 * and the optional ability to force a distance regardless of overlap.)
230 * To see if the rectangle being added overlaps, first its east and
231 * west are tested. All previous rectangles that are "out of its way"
232 * horizontally are marked not "relevant"; the others are marked
233 * "relevant". As positions are tried, working outwards, positions
234 * that fail to avoid overlap are marked "tried". (For chords, and
235 * rom/ital/bold/boldital, previous rectangles that are closer to the
236 * staff than the stuff is allowed to come anyhow are pre-marked as if
241 * Fill rectab for the objects above this staff.
243 reclim
= 0; /* rectab is initially empty */
245 dostaff(s
, PL_ABOVE
);
246 dogroups(start_p
, s
, PL_ABOVE
);
247 dobeamalt(start_p
, s
, PL_ABOVE
);
248 docurve(start_p
, s
, PL_ABOVE
, DO_OTHERS
);
249 dotuplet(start_p
, s
, PL_ABOVE
);
250 docurve(start_p
, s
, PL_ABOVE
, DO_PHRASE
);
252 /* get stacking order of the user-controllable mark types */
253 order
= svpath(s
, ABOVEORDER
)->markorder
[PL_ABOVE
];
255 /* loop on each possible stacking order number */
256 for (stk
= 1; stk
<= NUM_MARK
; stk
++) {
258 /* set bit map for each mark type that has this order number */
260 for (mk
= 0; mk
< NUM_MARK
; mk
++) {
261 if (order
[mk
] == stk
) {
262 do_which
|= (1L << mk
);
265 /* if no marks, we're done; stacking orders are contiguous */
270 * Some mark types must have a unique order number, not shared
271 * with any others. For each of them, do a case statement to
272 * call their subroutine. The other ones all share the same
273 * subroutine, so call it in the default to do the mark types
274 * listed in the bit map.
277 case 1L << MK_LYRICS
:
278 dolyrics(start_p
, s
, PL_ABOVE
);
280 case 1L << MK_ENDING
:
281 doendings(start_p
, s
);
283 case 1L << MK_REHEARSAL
:
284 dorehears(start_p
, s
);
287 break; /* ignore for above */
289 domiscstuff(start_p
, s
, PL_ABOVE
, do_which
);
295 * Find the northernmost rectangle, for setting the staff's north.
296 * But don't let north be so close that things sticking out might
297 * almost touch another staff. Staffs smaller than a regular 5 line
298 * staff will still be given as much space. In any case, we want at
299 * least 3 stepsizes of white space.
301 north
= staffvertspace(s
) / 2.0 + 3.0 * Stepsize
;
302 for (k
= 0; k
< reclim
; k
++) {
303 if (rectab
[k
].n
> north
)
308 * Fill rectab for the objects below this staff.
310 reclim
= 0; /* rectab is initially empty */
312 dostaff(s
, PL_BELOW
);
313 dogroups(start_p
, s
, PL_BELOW
);
314 dobeamalt(start_p
, s
, PL_BELOW
);
315 docurve(start_p
, s
, PL_BELOW
, DO_OTHERS
);
316 dotuplet(start_p
, s
, PL_BELOW
);
317 docurve(start_p
, s
, PL_BELOW
, DO_PHRASE
);
319 /* get stacking order of the user-controllable mark types */
320 order
= svpath(s
, BELOWORDER
)->markorder
[PL_BELOW
];
322 /* loop on each possible stacking order number */
323 for (stk
= 1; stk
<= NUM_MARK
; stk
++) {
325 /* set bit map for each mark type that has this order number */
327 for (mk
= 0; mk
< NUM_MARK
; mk
++) {
328 if (order
[mk
] == stk
) {
329 do_which
|= (1L << mk
);
332 /* if no marks, we're done; stacking orders are contiguous */
337 * Some mark types must have a unique order number, not shared
338 * with any others. For each of them, do a case statement to
339 * call their subroutine. The other ones all share the same
340 * subroutine, so call it in the default to do the mark types
341 * listed in the bit map.
344 case 1L << MK_LYRICS
:
345 dolyrics(start_p
, s
, PL_BELOW
);
347 case 1L << MK_ENDING
:
348 case 1L << MK_REHEARSAL
:
349 break; /* ignore for below */
354 domiscstuff(start_p
, s
, PL_BELOW
, do_which
);
360 * Find the southernmost rectangle, for setting the staff's south.
361 * But don't let south be so close that things sticking out might
362 * almost touch another staff. Staffs smaller than a regular 5 line
363 * staff will still be given as much space. In any case, we want at
364 * least 3 stepsizes of white space.
366 south
= -(staffvertspace(s
) / 2.0 + 3.0 * Stepsize
);
367 for (k
= 0; k
< reclim
; k
++) {
368 if (rectab
[k
].s
< south
)
373 * Fill rectab for the objects between this staff and the one below.
375 reclim
= 0; /* rectab is initially empty */
377 /* set up baseline, a rectangle of height 0 spanning the page */
378 rectab
[reclim
].w
= 0;
379 rectab
[reclim
].e
= PGWIDTH
;
380 rectab
[reclim
].n
= 0;
381 rectab
[reclim
].s
= 0;
385 /* get stacking order of the user-controllable mark types */
386 order
= svpath(s
, BETWEENORDER
)->markorder
[PL_BETWEEN
];
388 /* loop on each possible stacking order number */
389 for (stk
= 1; stk
<= NUM_MARK
; stk
++) {
391 /* set bit map for each mark type that has this order number */
393 for (mk
= 0; mk
< NUM_MARK
; mk
++) {
394 if (order
[mk
] == stk
) {
395 do_which
|= (1L << mk
);
398 /* if no marks, we're done; stacking orders are contiguous */
403 * Some mark types must have a unique order number, not shared
404 * with any others. For each of them, do a case statement to
405 * call their subroutine. The other ones all share the same
406 * subroutine, so call it in the default to do the mark types
407 * listed in the bit map.
410 case 1L << MK_LYRICS
:
411 dolyrics(start_p
, s
, PL_BETWEEN
);
413 case 1L << MK_ENDING
:
414 case 1L << MK_REHEARSAL
:
416 break; /* ignore for between */
418 domiscstuff(start_p
, s
, PL_BETWEEN
, do_which
);
424 * Find the northernmost rectangle, for finding the height of these
428 for (k
= 0; k
< reclim
; k
++) {
429 if (rectab
[k
].n
> hb
)
434 * Set the relative north and south of every STAFF structure for this
435 * staff number on this score. (There's one per measure.) While
436 * we're at it, set RX to 0, in case anyone cares. Set the height of
437 * "between" objects in each STAFF, too.
439 for (mainll_p
= start_p
->next
; mainll_p
!= 0 &&
440 mainll_p
->str
!= S_FEED
; mainll_p
= mainll_p
->next
) {
442 if (mainll_p
->str
== S_STAFF
&&
443 mainll_p
->u
.staff_p
->staffno
== s
) {
445 mainll_p
->u
.staff_p
->c
[RN
] = north
;
446 mainll_p
->u
.staff_p
->c
[RX
] = 0;
447 mainll_p
->u
.staff_p
->c
[RS
] = south
;
448 mainll_p
->u
.staff_p
->heightbetween
= hb
;
456 * Abstract: Set up the rectangle for the staff itself.
460 * Description: This function puts into rectab the rectangle for the staff
461 * itself. The staff's relative vertical coords are not set now,
462 * though, because they must later be set to include all the
463 * objects associated with the staff.
469 int s
; /* staff number */
470 int place
; /* above or below? */
473 debug(32, "dostaff s=%d place=%d", s
, place
);
475 * Use the full page width, even though the staff will not actually
476 * reach the edges, due to margins, etc. This way nothing will ever
477 * fall beyond this base rectangle. Put a STDPAD of padding around
480 rectab
[reclim
].w
= 0;
481 rectab
[reclim
].e
= PGWIDTH
;
483 if (place
== PL_ABOVE
) {
484 rectab
[reclim
].n
= halfstaffhi(s
) + Stdpad
;
485 rectab
[reclim
].s
= 0;
486 } else { /* PL_BELOW */
487 rectab
[reclim
].n
= 0;
488 rectab
[reclim
].s
= -(halfstaffhi(s
) + Stdpad
);
497 * Abstract: Set up rectangles & relative vert coords for staff's groups.
501 * Description: This function puts into rectab the rectangles for each group on
502 * this staff. The groups' relative vertical coords were already
503 * set in proclist() in beamstem.c.
507 dogroups(start_p
, s
, place
)
509 struct MAINLL
*start_p
; /* FEED at the start of this score */
510 int s
; /* staff number */
511 int place
; /* above or below? */
514 struct MAINLL
*mainll_p
; /* point along main linked list */
515 int v
; /* voice number */
518 debug(32, "dogroups file=%s line=%d s=%d place=%d", start_p
->inputfile
,
519 start_p
->inputlineno
, s
, place
);
521 * Loop through this score's part of the MLL.
523 for (mainll_p
= start_p
->next
; mainll_p
!= 0 &&
524 mainll_p
->str
!= S_FEED
; mainll_p
= mainll_p
->next
) {
526 * Whenever we find a structure for this staff (another
527 * measure of this staff), call llgrps() for each voice.
528 * If some voice doesn't exist, llgrps() will get a
529 * null pointer and just return.
531 if (mainll_p
->str
== S_STAFF
&&
532 mainll_p
->u
.staff_p
->staffno
== s
) {
534 for (v
= 0; v
< MAXVOICES
; v
++)
535 llgrps(mainll_p
->u
.staff_p
,
536 mainll_p
->u
.staff_p
->groups_p
[v
], place
);
544 * Abstract: Set up rectangles for note and rest groups.
548 * Description: This function puts rectangles into rectab for all groups in
549 * this measure of this voice, for groups consisting of notes or
554 llgrps(staff_p
, first_p
, place
)
556 struct STAFF
*staff_p
; /* point to the staff */
557 struct GRPSYL
*first_p
; /* point to first group */
558 int place
; /* above or below? */
561 struct GRPSYL
*gs_p
; /* point at a group */
562 struct NOTE
*note_p
; /* point at a note */
563 double mx
, my_offset
, mheight
, mwidth
; /* multirest number coords */
564 int n
; /* loop through notelist */
565 float asc
, des
, wid
; /* ascent, descent, and width of acc */
569 * For each group that is notes or a rest, put a rectangle into rectab.
570 * However, on tablature staffs, don't do this for rests, since they
571 * aren't printed there.
573 for (gs_p
= first_p
; gs_p
!= 0; gs_p
= gs_p
->next
) {
574 if (gs_p
->grpcont
== GC_SPACE
)
577 if (gs_p
->grpcont
== GC_REST
&& is_tab_staff(gs_p
->staffno
))
580 if (place
== PL_ABOVE
&& (
581 gs_p
->basictime
< -1 && svpath(staff_p
->staffno
,
582 PRINTMULTNUM
)->printmultnum
== YES
||
583 is_mrpt(gs_p
) && svpath(staff_p
->staffno
,
584 NUMBERMRPT
)->numbermrpt
== YES
587 * Special case for multirests and measure repeats.
588 * The rest or mrpt symbol itself is inside the staff,
589 * so we don't have to worry about it. But we need to
590 * make a rectangle for the number, if the number is
593 (void)mrnum(staff_p
, &mx
, &my_offset
, &mheight
,
595 rectab
[reclim
].w
= mx
;
596 rectab
[reclim
].e
= mx
+ mwidth
;
597 rectab
[reclim
].n
= my_offset
+ mheight
;
598 rectab
[reclim
].s
= 0;
604 /* for "below", no rectangles are needed for multirests */
605 if (gs_p
->basictime
< -1)
609 * We have a normal note or rest group. Make a rectangle for
610 * it, making sure it reaches the center staff line.
612 rectab
[reclim
].w
= gs_p
->c
[AW
];
613 rectab
[reclim
].e
= gs_p
->c
[AE
];
615 if (place
== PL_ABOVE
) {
616 rectab
[reclim
].n
= MAX(gs_p
->c
[RN
], 0);
617 rectab
[reclim
].s
= 0;
618 } else { /* PL_BELOW */
619 rectab
[reclim
].n
= 0;
620 rectab
[reclim
].s
= MIN(gs_p
->c
[RS
], 0);
625 /* if a clef precedes this group, make a rectangle for it */
626 if (gs_p
->clef
!= NOCLEF
) {
627 float north
, south
; /* clef coords */
629 rectab
[reclim
].e
= gs_p
->c
[AW
] - Staffscale
* CLEFPAD
;
630 rectab
[reclim
].w
= rectab
[reclim
].e
- Staffscale
*
631 clefwidth(gs_p
->clef
, YES
);
632 (void)clefvert(gs_p
->clef
, YES
, &north
, &south
);
633 rectab
[reclim
].n
= north
* Staffscale
;
634 rectab
[reclim
].s
= south
* Staffscale
;
640 * An additional rectangle is needed for each note that has an
641 * accidental. This is because although the east/west group
642 * boundaries include any accidentals, the north/south
643 * boundaries ingore them. It needs to be this way because,
644 * for other reasons, like ties, we want the north/south group
645 * boundaries to consider only the note heads. But for general
646 * stuff, the accidentals should also be considered. The
647 * rectangles added below take care of this.
648 * Similarly, if the top or bottom note is on a line and has a
649 * dot in the space away from the group, it needs a rectangle.
651 if (gs_p
->grpcont
== GC_NOTES
&&
652 ! is_tab_staff(gs_p
->staffno
)) {
653 for (n
= 0; n
< gs_p
->nnotes
; n
++) {
654 note_p
= &gs_p
->notelist
[n
];
656 if (gs_p
->dots
!= 0 &&
657 note_p
->stepsup
% 2 == 0 &&
658 (n
== 0 && note_p
->ydotr
> 0.0 ||
659 n
== gs_p
->nnotes
- 1 && note_p
->ydotr
< 0.0)){
660 float radius
; /* of a dot, + pad */
661 radius
= Stdpad
+ Staffscale
*
662 ascent(FONT_MUSIC
, (note_p
->
663 notesize
== GS_NORMAL ?
664 DFLT_SIZE
: SMALLSIZE
), C_DOT
);
665 rectab
[reclim
].n
= gs_p
->c
[RY
] +
666 note_p
->ydotr
+ radius
;
667 rectab
[reclim
].s
= gs_p
->c
[RY
] +
668 note_p
->ydotr
- radius
;
669 rectab
[reclim
].w
= gs_p
->c
[AX
] +
670 gs_p
->xdotr
- radius
;
671 rectab
[reclim
].e
= gs_p
->c
[AX
] +
672 gs_p
->xdotr
+ radius
+
673 (gs_p
->dots
- 1) * 2.0 *
678 if (note_p
->accidental
== '\0')
681 /* this note has an acc; create a rectangle */
682 accdimen(note_p
, &asc
, &des
, &wid
);
687 rectab
[reclim
].w
= gs_p
->c
[AX
] + note_p
->waccr
;
688 rectab
[reclim
].e
= rectab
[reclim
].w
+ wid
;
689 rectab
[reclim
].n
= note_p
->c
[RY
] + asc
;
690 rectab
[reclim
].s
= note_p
->c
[RY
] - des
;
701 * Abstract: Set up rectangles for beams and alternation bars.
705 * Description: This function puts into rectab rectangles for each beam or
706 * alternation bar on this staff in this score, where the thing
707 * is on the "place" side of the notes.
711 dobeamalt(start_p
, s
, place
)
713 struct MAINLL
*start_p
; /* FEED at the start of this score */
714 int s
; /* staff number */
715 int place
; /* above or below? */
718 struct MAINLL
*mainll_p
; /* point along main linked list */
719 struct GRPSYL
*gs_p
; /* point along a GRPSYL linked list */
720 int v
; /* voice number */
723 debug(32, "dobeamalt file=%s line=%d s=%d place=%d", start_p
->inputfile
,
724 start_p
->inputlineno
, s
, place
);
726 * Loop through this score's part of the MLL.
728 for (mainll_p
= start_p
->next
; mainll_p
!= 0 &&
729 mainll_p
->str
!= S_FEED
; mainll_p
= mainll_p
->next
) {
731 * Whenever we find a structure for this staff (another
732 * measure of this staff), loop through its voices.
734 if (mainll_p
->str
== S_STAFF
&&
735 mainll_p
->u
.staff_p
->staffno
== s
) {
737 for (v
= 0; v
< MAXVOICES
; v
++) {
738 for (gs_p
= mainll_p
->u
.staff_p
->groups_p
[v
];
739 gs_p
!= 0; gs_p
= gs_p
->next
) {
741 * Whenever we find the first group of
742 * a nongrace beamed or alted set with
743 * the stem direction on the side we
744 * are dealing with, call onebeamalt()
745 * to put rectangle(s) in rectab.
746 * But not for cross staff beams.
747 * Grace groups are included in the
748 * following nongrace group's rectangle
751 if (gs_p
->grpcont
== GC_NOTES
&&
752 gs_p
->grpvalue
== GV_NORMAL
&&
753 gs_p
->beamloc
== STARTITEM
&&
754 gs_p
->beamto
== CS_SAME
) {
756 if (place
== PL_ABOVE
&&
757 gs_p
->stemdir
== UP
||
759 gs_p
->stemdir
== DOWN
)
772 * Abstract: Set up rectangle(s) for one beam or alternation bar.
776 * Description: This function puts zero or more rectangles in rectab for the
777 * beam or alternation that starts at the given group. The longer
778 * and more slanted the beam/alternation is, the more rectangles
779 * will be necessary to enclose it without wasting a lot of space.
780 * If the beam/alt lies within the staff, there's no need to make
781 * any rectangles. All rectangles' inner edges are the center
788 struct GRPSYL
*gs_p
; /* initially points to first group */
791 float stemshift
; /* how far a stem is from its group's X */
792 float x1
, y1
; /* coords of left end of beam/alt */
793 float x2
, y2
; /* coords of right end of beam/alt */
797 * Set coords of the ends of the beam/alt. We are given the first
798 * group, but must search forward to the end to find the last group,
799 * being careful to ignore embedded grace groups. We adjust the X
800 * coords (for groups that can have stems) because stems are offset
801 * from their group's X. The Y coords can't always be based on the
802 * group boundaries, because there might be "with" lists on the
803 * abnormal (beam) side, and they don't affect the position of the beam.
806 y1
= getstemendvert(gs_p
);
808 while (gs_p
!= 0 && (gs_p
->grpvalue
== GV_ZERO
||
809 gs_p
->beamloc
!= ENDITEM
))
812 pfatal("beam or alt group has no ENDITEM");
815 y2
= getstemendvert(gs_p
);
817 stemshift
= getstemshift(gs_p
);
819 if (gs_p
->basictime
>= 2) {
820 /* the groups have stems (if first one does, others must too)*/
821 if (gs_p
->stemdir
== UP
) {
830 /* make zero or more rectangles for this beam/alt */
831 linerects(x1
, y1
, x2
, y2
, gs_p
->stemdir
, halfstaffhi(gs_p
->staffno
));
835 * Name: getstemendvert()
837 * Abstract: Find the vertical coord of the end of a stem.
841 * Description: This function is given a GRPSYL of a group that has either a
842 * real, visible stem, or an invisible one (alt). If finds
843 * the relative vertical coordinate of the end of the stems
844 * farthest from the note head(s).
850 struct GRPSYL
*gs_p
; /* the group in question */
853 double y
; /* the answer */
856 if (gs_p
->nwith
== 0 || gs_p
->normwith
== YES
) {
858 * Either there is no "with" list, or it's on the notes' end
859 * of the stem. So we can use the group boundary.
861 y
= gs_p
->stemdir
== UP ? gs_p
->c
[RN
] : gs_p
->c
[RS
];
864 * There is a "with" list at this end of the stem. Find where
865 * the end of the stem is by applying the stem's length to the
866 * farthest note on the opposite side.
868 if (gs_p
->stemdir
== UP
)
869 y
= gs_p
->notelist
[ gs_p
->nnotes
- 1 ].c
[RY
] +
872 y
= gs_p
->notelist
[ 0 ].c
[RY
] - gs_p
->stemlen
;
875 /* counteract the stem shortening that was done in finalstemadjust() */
876 if (gs_p
->beamloc
!= NOITEM
) {
877 if (gs_p
->stemdir
== UP
) {
878 y
+= (W_WIDE
* Stdpad
/ 2.0);
880 y
-= (W_WIDE
* Stdpad
/ 2.0);
890 * Abstract: Set up rectangle(s) to contain a (possibly) slanted line.
894 * Description: This function puts zero or more rectangles in rectab to contain
895 * a (possibly) slanted line. The longer and more slanted the
896 * line is, the more rectangles will be necessary to enclose it
897 * without wasting a lot of space. If the line lies within the
898 * staff, there's no need to make any rectangles. All rectangles'
899 * inner edges are the center staff line.
903 linerects(x1
, y1
, x2
, y2
, side
, halfstaff
)
905 double x1
, y1
; /* coords of left end of line */
906 double x2
, y2
; /* coords of right end of line */
907 int side
; /* side to favor, UP or DOWN */
908 double halfstaff
; /* half the staff height */
911 float slope
, yintercept
;/* of a line a STDPAD beyond beam/alt */
912 float deltax
; /* width of one rectangle */
913 float leftx
, rightx
; /* X coord of sides of a rectangle */
916 /* if line is within staff, no need for any rectangles */
917 if (fabs(y1
) < halfstaff
&& fabs(y2
) < halfstaff
)
921 * If this beam/alt is level, make one big rectangle, and get out.
924 rectab
[reclim
].w
= x1
;
925 rectab
[reclim
].e
= x2
;
927 rectab
[reclim
].n
= y1
;
928 rectab
[reclim
].s
= 0;
930 rectab
[reclim
].n
= 0;
931 rectab
[reclim
].s
= y1
;
938 * We may need multiple rectangles. Make them narrow enough so that
939 * the change in Y across the width of one is one STEPSIZE. The
940 * rightmost one will probably be narrower, using whatever room
941 * remains. The equation of our line is y = slope * x + yintercept.
943 slope
= (y1
- y2
) / (x1
- x2
);
944 yintercept
= y1
- slope
* x1
;
945 deltax
= Stepsize
/ fabs(slope
);
947 for (leftx
= x1
; leftx
< x2
; leftx
+= deltax
) {
948 rightx
= MIN(x2
, leftx
+ deltax
);
949 rectab
[reclim
].w
= leftx
;
950 rectab
[reclim
].e
= rightx
;
952 rectab
[reclim
].n
= slope
* (slope
> 0 ? rightx
: leftx
)
954 rectab
[reclim
].s
= 0;
956 rectab
[reclim
].n
= 0;
957 rectab
[reclim
].s
= slope
* (slope
> 0 ? leftx
: rightx
)
967 * Abstract: Get point list and set up rectangles for tie/slur/bend/phrase.
971 * Description: This function goes through all ties, slurs, bends, phrases for
972 * staff. The first time it is called for a staff (which is for
973 * place "above") it calls a function to set up the curve list.
974 * Whichever time it is called, it calls a function to put
975 * rectangles in rectab.
979 docurve(start_p
, s
, place
, do_which
)
981 struct MAINLL
*start_p
; /* FEED at the start of this score */
982 int s
; /* staff number */
983 int place
; /* above or below? */
984 int do_which
; /* which stuff types are to be handled */
987 struct MAINLL
*mainll_p
; /* loop through main linked list */
988 struct STUFF
*stuff_p
; /* point along a STUFF list */
989 float halfstaff
; /* half the staff height */
992 debug(32, "docurve file=%s line=%d s=%d place=%d do_which=%d",
993 start_p
->inputfile
, start_p
->inputlineno
, s
, place
, do_which
);
994 halfstaff
= halfstaffhi(s
);
997 * Loop through this score's part of the MLL, looking for matching
1000 for (mainll_p
= start_p
->next
; mainll_p
!= 0 &&
1001 mainll_p
->str
!= S_FEED
; mainll_p
= mainll_p
->next
) {
1003 if (mainll_p
->str
!= S_STAFF
||
1004 mainll_p
->u
.staff_p
->staffno
!= s
)
1007 /* loop through each stuff of the indicated type */
1008 for (stuff_p
= mainll_p
->u
.staff_p
->stuff_p
;
1009 stuff_p
!= 0; stuff_p
= stuff_p
->next
){
1011 switch (stuff_p
->stuff_type
) {
1016 break; /* docurve works on these */
1018 continue; /* for some other function */
1022 * If we are to do phrases and this is not a phrase, or
1023 * vice versa, skip this.
1025 if ((do_which
== DO_PHRASE
) !=
1026 (stuff_p
->stuff_type
== ST_PHRASE
))
1030 * When we're in here the first time (for PL_ABOVE),
1031 * call a function to set up the curve list. For
1032 * everything but ST_PHRASE it also sets "place".
1034 if (place
== PL_ABOVE
) {
1035 switch (stuff_p
->stuff_type
) {
1037 /* don't call tieslur_points now if the
1038 * positions of the tie/slur's endpoints
1039 * would change later due to CSS */
1040 if (css_affects_tieslurbend(stuff_p
,
1044 tieslur_points(mainll_p
, stuff_p
);
1047 tabslur_points(mainll_p
, stuff_p
);
1050 /* don't call bend_points now if the
1051 * positions of the bend's endpoints
1052 * would change later due to CSS */
1053 if (css_affects_tieslurbend(stuff_p
,
1057 bend_points(mainll_p
, stuff_p
);
1060 /* don't call phrase_points now if the
1061 * positions of the phrase's endpoints
1062 * would change later due to CSS */
1063 if (css_affects_phrase(stuff_p
,
1067 phrase_points(mainll_p
, stuff_p
);
1073 * Make rectangles no matter what side of the staff the
1074 * curve is supposed to be on, because, depending on
1075 * how high or low the notes are, rectangles may be
1076 * needed even on the opposite side you'd expect.
1078 if (stuff_p
->crvlist_p
!= 0) {
1079 curverect(s
, stuff_p
, halfstaff
);
1088 * Abstract: Put rectangles in rectab for a tie, slur, bend, or phrase.
1092 * Description: This function puts rectangles in rectab for a tie, slur, bend,
1093 * or phrase. Each segment of the curve gets one or more
1094 * rectangles, depending on how long and how slanted it is. To do
1095 * this, we call curvepiecerect().
1099 curverect(s
, stuff_p
, halfstaff
)
1101 int s
; /* staff number */
1102 struct STUFF
*stuff_p
; /* the curve's STUFF */
1103 double halfstaff
; /* half the staff height */
1106 struct CRVLIST
*point_p
; /* point at a phrase point */
1107 float x1
, y1
; /* coords of left end of a segment */
1108 float x2
, y2
; /* coords of right end of a segment */
1109 float midx
, midy
; /* middle of one segment of a curve */
1113 * Loop through the curve list. For each pair of neighboring points,
1114 * there is a segment of the curve. For items that are actually
1115 * straight line segments, call curvepiecerect() once. But for actual
1116 * curves, find the midpoint, and call curvepiecerect() for each half.
1117 * This way we more closely approximate the real curve.
1119 for (point_p
= stuff_p
->crvlist_p
; point_p
->next
!= 0;
1120 point_p
= point_p
->next
) {
1124 x2
= point_p
->next
->x
;
1125 y2
= point_p
->next
->y
;
1127 if (stuff_p
->stuff_type
== ST_BEND
||
1128 stuff_p
->stuff_type
== ST_TABSLUR
) {
1129 /* bend, or slur on tab or tabnote */
1130 curvepiecerect(x1
, y1
, x2
, y2
, halfstaff
);
1133 midx
= (x1
+ x2
) / 2.0;
1134 midy
= curve_y_at_x(stuff_p
->crvlist_p
, midx
);
1135 curvepiecerect(x1
, y1
, midx
, midy
, halfstaff
);
1136 curvepiecerect(midx
, midy
, x2
, y2
, halfstaff
);
1142 * Name: curvepiecerect()
1144 * Abstract: Put rects in rectab for a piece of a tie, slur, bend, or phrase.
1148 * Description: This function puts rectangles in rectab for one piece of a
1149 * curve. The piece gets one or more rectangles, depending on how
1150 * long and how slanted it is.
1154 curvepiecerect(x1
, y1
, x2
, y2
, halfstaff
)
1156 double x1
, y1
; /* coords of left end of the piece */
1157 double x2
, y2
; /* coords of right end of the piece */
1158 double halfstaff
; /* half the staff height */
1161 float slope
, yintercept
;/* of a line a segment */
1162 float deltax
; /* width of one rectangle */
1163 float leftx
, rightx
; /* X coord of sides of a rectangle */
1166 /* if whole piece is within the staff, no rectangles are needed */
1167 if (fabs(y1
) < halfstaff
&& fabs(y2
) < halfstaff
)
1171 * If this piece is level, make 1 big rectangle, and continue.
1174 rectab
[reclim
].w
= x1
;
1175 rectab
[reclim
].e
= x2
;
1176 rectab
[reclim
].n
= MAX(y1
+ 2 * Stdpad
, 0.0);
1177 rectab
[reclim
].s
= MIN(y1
- 2 * Stdpad
, 0.0);
1183 * We may need multiple rectangles. Make them narrow enough so that
1184 * the change in Y across the width of one is one Stepsize. The
1185 * rightmost one will probably be narrower, using whatever room
1186 * remains. The equation of our line is
1187 * y = slope * x + yintercept
1188 * Initially each rectangle only includes its segment (plus padding),
1189 * but then we extend it to reach the center line of the staff.
1191 slope
= (y1
- y2
) / (x1
- x2
);
1192 yintercept
= y1
- slope
* x1
;
1193 deltax
= Stepsize
/ fabs(slope
);
1195 for (leftx
= x1
; leftx
< x2
; leftx
+= deltax
) {
1196 rightx
= MIN(x2
, leftx
+ deltax
);
1198 rectab
[reclim
].w
= leftx
;
1199 rectab
[reclim
].e
= rightx
;
1202 * For north and south boundaries, use the side of the rect
1203 * that sticks out more, to err on the side of making the rect
1204 * big enough. Also add in padding, to 1) allow for the fact
1205 * that the real curve probably bulges out beyond our segment
1206 * approximation, and 2) because we don't want anything
1207 * actually touching the curve.
1209 rectab
[reclim
].n
= slope
* (slope
> 0.0 ? rightx
: leftx
) +
1210 yintercept
+ 2.0 * Stdpad
;
1211 rectab
[reclim
].s
= slope
* (slope
< 0.0 ? rightx
: leftx
) +
1212 yintercept
- 2.0 * Stdpad
;
1214 /* rectangle must reach the center line of the staff */
1215 if (rectab
[reclim
].n
< 0.0)
1216 rectab
[reclim
].n
= 0.0;
1217 if (rectab
[reclim
].s
> 0.0)
1218 rectab
[reclim
].s
= 0.0;
1227 * Abstract: Set up rectangles for tuplet brackets.
1231 * Description: This function puts into rectab rectangles for each tuplet
1232 * bracket on this staff in this score, where the thing is on
1233 * the "place" side of the notes.
1238 dotuplet(start_p
, s
, place
)
1240 struct MAINLL
*start_p
; /* FEED at the start of this score */
1241 int s
; /* staff number */
1242 int place
; /* above or below? */
1245 struct MAINLL
*mainll_p
; /* point along main linked list */
1246 struct GRPSYL
*gs_p
; /* point along a GRPSYL linked list */
1247 int v
; /* voice number */
1250 debug(32, "dotuplet file=%s line=%d s=%d place=%d", start_p
->inputfile
,
1251 start_p
->inputlineno
, s
, place
);
1253 /* tuplet brackets are never printed on tablature staffs */
1254 if (is_tab_staff(s
))
1258 * Loop through this score's part of the MLL.
1260 for (mainll_p
= start_p
->next
; mainll_p
!= 0 &&
1261 mainll_p
->str
!= S_FEED
; mainll_p
= mainll_p
->next
) {
1263 * Whenever we find a structure for this staff (another
1264 * measure of this staff), loop through its voices.
1266 if (mainll_p
->str
== S_STAFF
&&
1267 mainll_p
->u
.staff_p
->staffno
== s
) {
1269 for (v
= 0; v
< MAXVOICES
; v
++) {
1270 for (gs_p
= mainll_p
->u
.staff_p
->groups_p
[v
];
1271 gs_p
!= 0; gs_p
= gs_p
->next
) {
1273 * Whenever we find the first group of
1274 * a tuplet with a bracket on the
1275 * "place" side of the group, call
1276 * onetuplet() to put rectangle(s) in
1279 if ((gs_p
->tuploc
== STARTITEM
||
1280 gs_p
->tuploc
== LONEITEM
) &&
1281 gs_p
->printtup
!= PT_NEITHER
) {
1283 if (tupdir(gs_p
, mainll_p
->u
.
1286 onetuplet(mainll_p
->u
.
1287 staff_p
, gs_p
, place
);
1298 * Abstract: Set up rectangle(s) for one tuplet bracket or number.
1302 * Description: If this tuplet is not going to be given a bracket (like because
1303 * its notes are already beamed), this function just makes one
1304 * rectangle, for the number. Otherwise, this function puts zero
1305 * or more rectangles in rectab for the tuplet that starts at the
1306 * given group. The longer and more slanted the tuplet bracket
1307 * is, the more rectangles will be necessary to enclose it without
1308 * wasting a lot of space. All rectangles' inner edges are the
1309 * center staff line.
1313 onetuplet(staff_p
, start_p
, place
)
1315 struct STAFF
*staff_p
; /* point to the staff we're on */
1316 struct GRPSYL
*start_p
; /* points to first group in tuplet */
1317 int place
; /* above or below? */
1320 struct GRPSYL
*gs_p
; /* point to a group in tuplet */
1321 float stemshift
; /* how far a stem is from its group's X */
1322 float x1
, y1
; /* coords of left end of beam/alt */
1323 float x2
, y2
; /* coords of right end of beam/alt */
1324 float numeast
, numwest
; /* horizontal coords of the tuplet number */
1325 float height
; /* height of the tuplet number */
1329 * Set coords of the ends of the tuplet. We are given the first
1330 * group, but must search forward to the end to find the last group,
1331 * being careful to ignore embedded grace groups. We adjust the X
1332 * coords because brackets reach beyond their group's X.
1334 x1
= start_p
->c
[AX
];
1335 y1
= (place
== PL_ABOVE ? start_p
->c
[RN
] : start_p
->c
[RS
])
1336 + start_p
->tupextend
;
1338 for (gs_p
= start_p
; gs_p
!= 0 && (gs_p
->grpvalue
== GV_ZERO
||
1339 gs_p
->tuploc
!= ENDITEM
&& gs_p
->tuploc
!= LONEITEM
);
1343 pfatal("tuplet has no ENDITEM");
1346 y2
= (place
== PL_ABOVE ? gs_p
->c
[RN
] : gs_p
->c
[RS
]) + gs_p
->tupextend
;
1349 * If there is not going to be a bracket, create one rectangle for the
1350 * tuplet number, and return.
1352 if (tupgetsbrack(start_p
) == NO
) {
1353 (void)tupnumsize(start_p
, &numwest
, &numeast
, &height
, staff_p
);
1354 rectab
[reclim
].n
= (y1
+ y2
) / 2 + height
/ 2;
1355 rectab
[reclim
].s
= (y1
+ y2
) / 2 - height
/ 2;
1356 rectab
[reclim
].w
= numwest
;
1357 rectab
[reclim
].e
= numeast
;
1363 /* there is going to be a bracket; extend x coords to reach to end */
1364 stemshift
= getstemshift(gs_p
);
1369 /* make zero or more rectangles for this bracket */
1370 linerects(x1
, y1
, x2
, y2
, place
== PL_ABOVE ? UP
: DOWN
,
1371 halfstaffhi(gs_p
->staffno
));
1375 * Name: domiscstuff()
1377 * Abstract: Set up rectangles and vert coords for miscellaneous STUFF.
1381 * Description: This function puts into rectab a rectangle for each STUFF
1382 * structure in the "place" relationship to the given staff on
1383 * this score, except for stuff types that have special,
1384 * dedicated functions for their type. It also sets their
1385 * relative vertical coordinates.
1389 domiscstuff(start_p
, s
, place
, do_which
)
1391 struct MAINLL
*start_p
; /* FEED at the start of this score */
1392 int s
; /* staff number */
1393 int place
; /* above, below, or between? */
1394 unsigned long do_which
; /* which stuff types are to be handled */
1397 struct MAINLL
*mainll_p
; /* loop through main linked list */
1398 struct STUFF
*stuff_p
; /* point along a STUFF list */
1399 float high
; /* height of a rectangle */
1400 float len
; /* length of a cresc/descresc */
1401 float lowpart
; /* dist between stuff's Y and S */
1402 float dist
; /* how close chord can get to staff */
1403 int stype
; /* stuff type */
1406 debug(32, "domiscstuff file=%s line=%d s=%d place=%d do_which=%ld",
1407 start_p
->inputfile
, start_p
->inputlineno
, s
, place
, do_which
);
1409 * Loop through this score's part of the MLL. Whenever we find a
1410 * structure for this staff (another measure), loop through its
1411 * STUFF list, dealing with each STUFF that is above, below, or
1412 * between, as specified by "place".
1414 for (mainll_p
= start_p
->next
; mainll_p
!= 0 &&
1415 mainll_p
->str
!= S_FEED
; mainll_p
= mainll_p
->next
) {
1417 if (mainll_p
->str
!= S_STAFF
||
1418 mainll_p
->u
.staff_p
->staffno
!= s
) {
1422 for (stuff_p
= mainll_p
->u
.staff_p
->stuff_p
;
1423 stuff_p
!= 0; stuff_p
= stuff_p
->next
) {
1425 if (stuff_p
->place
!= place
) {
1429 stype
= stuff_p
->stuff_type
;
1431 /* if wrong type for this pass, exit */
1432 if (stype
== ST_MUSSYM
) {
1433 if ((do_which
& (1L << MK_MUSSYM
)) == 0)
1435 } else if (stype
== ST_OCTAVE
) {
1436 if ((do_which
& (1L << MK_OCTAVE
)) == 0)
1438 } else if (stype
!= ST_PHRASE
&&
1439 stuff_p
->modifier
== TM_DYN
) {
1440 if ((do_which
& (1L << MK_DYN
)) == 0)
1442 } else if (stype
!= ST_PHRASE
&&
1443 IS_CHORDLIKE(stuff_p
->modifier
)) {
1444 if ((do_which
& (1L << MK_CHORD
)) == 0)
1446 } else if (IS_TEXT(stype
)) {
1447 if ((do_which
& (1L << MK_OTHERTEXT
)) == 0)
1452 * We found a "stuff" that needs to be positioned.
1453 * First find its total height, and the height of the
1454 * part of it below its Y coord.
1456 /* avoid 'used before set' warning */
1457 high
= lowpart
= 0.0;
1459 /* handle various types differently */
1467 /* don't handle these types here; */
1468 /* they have their own subroutines */
1477 /* high is string's height */
1478 high
= strheight( stuff_p
->string
);
1479 lowpart
= strdescent( stuff_p
->string
);
1482 * If a chord grid is to be printed under the
1483 * string, the Y and N of the stuff remain
1484 * unchanged, but its S is lowered by the total
1485 * height of the grid. So add its height to
1486 * both "high" and "lowpart".
1488 if (stuff_p
->modifier
== TM_CHORD
&& svpath(s
,
1489 GRIDSWHEREUSED
)->gridswhereused
== YES
) {
1490 struct GRID
*grid_p
;
1491 float gnorth
, gsouth
;
1493 grid_p
= findgrid(stuff_p
->string
);
1494 /* if none, skip this; stuff.c warned*/
1498 gridsize(grid_p
, stuff_p
->all ?
0 :
1499 mainll_p
->u
.staff_p
->staffno
,
1501 (float *)0, (float *)0);
1503 high
+= gnorth
- gsouth
;
1504 lowpart
+= gnorth
- gsouth
;
1510 /* height depends on length */
1511 len
= stuff_p
->c
[AE
] - stuff_p
->c
[AW
];
1514 high
= 2.00 * STEPSIZE
+ 2 * STDPAD
;
1516 high
= 2.67 * STEPSIZE
+ 2 * STDPAD
;
1518 high
= 3.33 * STEPSIZE
+ 2 * STDPAD
;
1521 high
*= Score
.staffscale
;
1530 pfatal("unknown stuff type (%d)", stype
);
1534 * Now find "dist", the minimum distance it should be
1535 * put from the staff.
1537 if (stuff_p
->dist_usage
== SD_NONE
) {
1539 * The user didn't specify the dist, so we get
1540 * it from the appropriate parameter or hard-
1541 * coded value, as the case may be. For
1542 * parameters, if the stuff belongs to the
1543 * score as a whole ("all"), use the Score
1544 * value instead of svpath.
1546 /* if "dyn", fake to use same logic as cresc */
1547 if (stuff_p
->modifier
== TM_DYN
)
1556 stuff_p
->modifier
)) {
1571 stuff_p
->modifier
)) {
1575 svpath(s
, CHORDDIST
)->
1581 svpath(s
, DIST
)->dist
;
1588 dist
= halfstaffhi(s
) +
1589 STEPSIZE
* Score
.staffscale
*
1592 dist
= halfstaffhi(s
) +
1593 Stepsize
* svpath(s
,
1602 /* the user specified the dist, so use that */
1604 dist
= halfstaffhi(s
) +
1605 STEPSIZE
* stuff_p
->dist
;
1607 dist
= halfstaffhi(s
) +
1608 Stepsize
* stuff_p
->dist
;
1612 if (stuff_p
->dist_usage
== SD_FORCE
) {
1614 * The user is forcing this dist, so don't
1615 * stack; just put it there. Note: the user
1616 * cannot specify "dist" for "between" items.
1618 if (stuff_p
->place
== PL_ABOVE
) {
1619 rectab
[reclim
].n
= dist
+ high
;
1620 rectab
[reclim
].s
= dist
;
1621 stuff_p
->c
[RS
] = dist
;
1622 } else { /* PL_BELOW */
1623 rectab
[reclim
].n
= -dist
;
1624 rectab
[reclim
].s
= -dist
- high
;
1625 stuff_p
->c
[RS
] = -dist
- high
;
1627 rectab
[reclim
].e
= stuff_p
->c
[AE
];
1628 rectab
[reclim
].w
= stuff_p
->c
[AW
];
1632 * Stack the usual way. For the case of
1633 * "between", stackit() will ignore "dist".
1635 stuff_p
->c
[RS
] = stackit(stuff_p
->c
[AW
],
1636 stuff_p
->c
[AE
], high
, dist
, place
);
1639 stuff_p
->c
[RN
] = stuff_p
->c
[RS
] + high
;
1640 stuff_p
->c
[RY
] = stuff_p
->c
[RS
] + lowpart
;
1648 * Abstract: Set up rectangles and vert coords for lyrics.
1652 * Description: This function puts into rectab a rectangle for each verse in
1653 * the "place" relationship to the given staff on this score.
1657 dolyrics(start_p
, s
, place
)
1659 struct MAINLL
*start_p
; /* FEED at the start of this score */
1660 int s
; /* staff number */
1661 int place
; /* above, below, or between? */
1664 int *versenums
; /* malloc'ed array of verse numbers in score */
1665 struct MAINLL
*mainll_p
;/* point along main linked list */
1666 struct STAFF
*staff_p
; /* point at a staff structure */
1667 struct GRPSYL
*gs_p
; /* point at a syllable */
1668 float protrude
; /* farthest protrusion of rectangle */
1669 int vfound
; /* number of verse numbers found in score */
1670 int v
; /* verse number */
1671 int begin
, end
, delta
; /* for looping over verses in proper order */
1672 float dist
; /* how close lyrics can get to staff */
1673 float farwest
, fareast
; /* farthest east and west of any syllable */
1674 float baseline
; /* baseline of a verse of syllables */
1675 float maxasc
, maxdes
; /* max ascent & descent of syllables */
1676 int gotverse0
; /* is there a verse 0 (centered verse)? */
1677 int gototherverse
; /* is there a normal verse (not 0)? */
1678 int n
, k
, j
; /* loop variables */
1681 debug(32, "dolyrics file=%s line=%d s=%d place=%d", start_p
->inputfile
,
1682 start_p
->inputlineno
, s
, place
);
1683 /* if there are no lyrics in this song, get out now */
1688 * Allocate an array containing room for all the verse numbers used in
1689 * this score. Maxverses is the number of verse numbers used in the
1690 * whole user input, so this will certainly be enough.
1692 MALLOCA(int, versenums
, Maxverses
);
1695 * Loop through this score's part of the MLL, noting whether verse 0
1696 * (the centered verse) and/or other verses exist on the "place" side
1697 * of the staff. We have to find this out before actually processing
1698 * the verses, because verse 0 is to be treated as a normal verse if
1699 * and only if there are no other verses.
1703 for (mainll_p
= start_p
->next
; mainll_p
!= 0 &&
1704 mainll_p
->str
!= S_FEED
; mainll_p
= mainll_p
->next
) {
1706 * Whenever we find a structure for this staff (another
1707 * measure of this staff), loop through its verse headcells.
1709 if (mainll_p
->str
== S_STAFF
&&
1710 mainll_p
->u
.staff_p
->staffno
== s
) {
1711 staff_p
= mainll_p
->u
.staff_p
;
1712 for (n
= 0; n
< staff_p
->nsyllists
; n
++) {
1713 if (staff_p
->sylplace
[n
] == place
) {
1714 if (staff_p
->syls_p
[n
]->vno
== 0)
1717 gototherverse
= YES
;
1723 /* if no verses, get out now */
1724 if (gotverse0
== NO
&& gototherverse
== 0) {
1730 * Loop through this score's part of the MLL, recording all the verse
1731 * numbers that occur on the "place" side of the staff in versenums[].
1732 * Verse 0 may or may not be included, depending on the above results.
1733 * Also set farwest and fareast.
1735 vfound
= 0; /* no verses have been found yet */
1736 farwest
= PGWIDTH
; /* init it all the way east */
1737 fareast
= 0; /* init it all the way west */
1738 for (mainll_p
= start_p
->next
; mainll_p
!= 0 &&
1739 mainll_p
->str
!= S_FEED
; mainll_p
= mainll_p
->next
) {
1741 * Whenever we find a structure for this staff (another
1742 * measure of this staff), loop through its verse headcells.
1744 if (mainll_p
->str
== S_STAFF
&&
1745 mainll_p
->u
.staff_p
->staffno
== s
) {
1747 staff_p
= mainll_p
->u
.staff_p
;
1749 for (n
= 0; n
< staff_p
->nsyllists
; n
++) {
1751 if (staff_p
->sylplace
[n
] == place
) {
1753 * We found a verse number. Search the
1754 * the array to see if it's already
1755 * been found. If not, insert it into
1756 * versenums[] in the right place, so
1757 * that they'll end up being in order
1758 * (actually, reverse order).
1760 v
= staff_p
->syls_p
[n
]->vno
;
1761 /* ignore verse 0 if others exist */
1762 if (v
== 0 && gototherverse
== YES
)
1764 for (k
= 0; k
< vfound
&&
1765 v
< versenums
[k
]; k
++) {
1768 if (k
== vfound
|| v
> versenums
[k
]) {
1769 for (j
= vfound
; j
> k
; j
--) {
1774 vfound
++; /* found one more */
1778 * If any syl sticks out farther than
1779 * any previous one, extend farwest or
1782 for (gs_p
= staff_p
->syls_p
[n
];
1783 gs_p
!= 0; gs_p
= gs_p
->next
) {
1785 if (gs_p
->c
[AW
] < farwest
)
1786 farwest
= gs_p
->c
[AW
];
1787 if (gs_p
->c
[AE
] > fareast
)
1788 fareast
= gs_p
->c
[AE
];
1796 * Enclose all the syllables of all the verses (of this place) in one
1797 * big rectangle. Pad on west and east by 8 step sizes. Pretend the
1798 * rectangle is PGHEIGHT high. We don't actually know yet how high
1799 * it is, and this will prevent it from getting between the staff and
1800 * anything else. Later in this function we will correct the entry
1801 * that stackit put in rectab, to reflect the true height. For above
1802 * and below cases, don't let it get any closer than 2 step sizes to
1803 * the staff. The half-height of a one-line staff is regarded as 1
1804 * instead of the true 0, to give a little breathing room.
1806 if (place
== PL_BETWEEN
)
1809 dist
= halfstaffhi(s
) + 2.0 * Stepsize
;
1811 (void)stackit(farwest
- 8 * STEPSIZE
, fareast
+ 8 * STEPSIZE
, PGHEIGHT
,
1815 * Find the greatest protrusion of any currently existing rectangle
1816 * that horizontally is within the span of our new rectangle. That's
1817 * the same as the top or bottom of the new rectangle.
1819 if (place
== PL_BELOW
)
1820 protrude
= rectab
[reclim
- 1].n
;
1822 protrude
= rectab
[reclim
- 1].s
;
1825 * Loop through the verses, from the inside out. setting the relative
1826 * vertical coords of their syllables. When necessary, we also insert
1827 * new syllables on the next score for continuing underscores.
1829 if (place
== PL_BELOW
) { /* work downward from staff */
1830 begin
= vfound
- 1; /* first verse number */
1831 end
= -1; /* beyond last verse number */
1833 } else { /* above and between both work upwards from bottom */
1834 begin
= 0; /* last verse number */
1835 end
= vfound
; /* before first verse number */
1838 for (n
= begin
; n
!= end
; n
+= delta
) {
1840 * Find the farthest any syllable ascends and descends from the
1841 * baseline of the verse.
1843 getvsize(start_p
, s
, place
, versenums
[n
], &maxasc
, &maxdes
);
1846 * Set the baseline for this verse, based on where we're
1847 * pushing up against (the last verse we did, or earlier
1848 * things), and how far this verse sticks out.
1850 if (place
== PL_BELOW
)
1851 baseline
= protrude
- maxasc
;
1852 else /* above or between */
1853 baseline
= protrude
+ maxdes
;
1855 /* set syllables' vertical coords; continue underscores */
1856 setsylvert(start_p
, s
, place
, versenums
[n
], baseline
);
1858 /* set new lower bound, for next time through loop */
1859 if (place
== PL_BELOW
)
1860 protrude
= baseline
- maxdes
;
1861 else /* above or between */
1862 protrude
= baseline
+ maxasc
;
1864 } /* for every verse */
1867 * If there was a verse 0 (centered verse) and also normal verses, then
1868 * in the above code we have handled only the normal verses, and we now
1869 * need to handle verse 0.
1871 if (gotverse0
== YES
&& gototherverse
== YES
) {
1872 float mid
; /* RY of the middle of the normal verses */
1873 struct RECTAB rec
; /* one rectangle */
1875 /* get ascent and descent of verse 0 */
1876 getvsize(start_p
, s
, place
, 0, &maxasc
, &maxdes
);
1879 * We will use stackit's "dist" mechanism to try to get verse 0
1880 * to line up with the center of the other verses. The last
1881 * rectangle in rectab is currently the normal verses', but the
1882 * one coord isn't really set right yet. Fortunately, the
1883 * "protrude" variable is what we need for that coord.
1885 if (place
== PL_BELOW
) {
1886 mid
= (rectab
[reclim
- 1].n
+ protrude
) / 2.0;
1887 dist
= -mid
- (maxasc
+ maxdes
) / 2.0;
1889 mid
= (protrude
+ rectab
[reclim
- 1].s
) / 2.0;
1890 dist
= mid
- (maxasc
+ maxdes
) / 2.0;
1894 * Find the easternmost and westernmost points of verse 0.
1895 * It's easier to loop through all the syllables than to try to
1896 * find the first and last syllables on the line.
1898 farwest
= PGWIDTH
; /* init it all the way east */
1899 fareast
= 0; /* init it all the way west */
1900 for (mainll_p
= start_p
->next
;
1901 mainll_p
!= 0 && mainll_p
->str
!= S_FEED
;
1902 mainll_p
= mainll_p
->next
) {
1904 if (mainll_p
->str
!= S_STAFF
||
1905 mainll_p
->u
.staff_p
->staffno
!= s
)
1908 staff_p
= mainll_p
->u
.staff_p
;
1909 for (n
= 0; n
< staff_p
->nsyllists
; n
++) {
1910 if (staff_p
->sylplace
[n
] == place
&&
1911 staff_p
->syls_p
[n
]->vno
== 0) {
1912 for (gs_p
= staff_p
->syls_p
[n
];
1913 gs_p
!= 0; gs_p
= gs_p
->next
) {
1915 if (gs_p
->c
[AW
] < farwest
)
1916 farwest
= gs_p
->c
[AW
];
1917 if (gs_p
->c
[AE
] > fareast
)
1918 fareast
= gs_p
->c
[AE
];
1925 * Squeeze the regular verses' rectangle to zero so that it
1926 * won't affect verse 0's. We hope they wouldn't interfere
1927 * anyway, but the +8 and -8 might make them. The regular
1928 * verses' rectangle will be corrected later anyway.
1930 rectab
[reclim
- 1].n
= rectab
[reclim
- 1].s
= 0;
1933 * Stack verse 0's rectangle and set its baseline. We have to
1934 * play games with "place", because for "between" stackit
1935 * ignores "dist", but we need it to use "dist".
1937 baseline
= stackit(farwest
- 8 * STEPSIZE
,
1938 fareast
+ 8 * STEPSIZE
, maxasc
+ maxdes
, dist
,
1939 place
== PL_BETWEEN ? PL_ABOVE
: place
) + maxdes
;
1942 * Switch verse 0's rectangle and the normal verses' so that
1943 * the later code can always use reclim-1 for the normal.
1945 rec
= rectab
[reclim
- 2];
1946 rectab
[reclim
- 2] = rectab
[reclim
- 1];
1947 rectab
[reclim
- 1] = rec
;
1949 setsylvert(start_p
, s
, place
, 0, baseline
);
1953 * Now that we know how high this rectangle really is, correct it in
1954 * rectab. Make it reach the center of the staff/baseline, to prevent
1955 * anything later from getting in between there.
1957 if (place
== PL_BELOW
) {
1958 rectab
[reclim
- 1].n
= 0;
1959 rectab
[reclim
- 1].s
= protrude
;
1960 } else { /* above or between */
1961 rectab
[reclim
- 1].n
= protrude
;
1962 rectab
[reclim
- 1].s
= 0;
1971 * Abstract: Get the maximum ascent and descent for a verse on a score.
1975 * Description: This function returns (through pointers) the maximum ascent and
1976 * descent of a verse on this score. Usually this is the standard
1977 * ascent and descent of the font, but it could be greater if
1978 * there are font or size changes inside some syllable.
1982 getvsize(start_p
, s
, place
, v
, maxasc_p
, maxdes_p
)
1984 struct MAINLL
*start_p
; /* FEED at the start of this score */
1985 int s
; /* staff number */
1986 int place
; /* above, below, or between? */
1987 int v
; /* verse number */
1988 float *maxasc_p
, *maxdes_p
; /* ascent and descent to be returned */
1991 int lyricsfont
; /* that is set for this staff */
1992 int lyricssize
; /* that is set for this staff */
1993 float asc
, des
; /* max ascent & descent of syllables */
1994 struct MAINLL
*mainll_p
;/* point along main linked list */
1995 struct STAFF
*staff_p
; /* point at a staff structure */
1996 struct GRPSYL
*gs_p
; /* point at a syllable */
1997 int k
; /* loop variable */
2001 * Get the standard max ascent and descent for any syllable.
2003 lyricsfont
= svpath(s
, LYRICSFONT
)->lyricsfont
;
2004 lyricssize
= svpath(s
, LYRICSSIZE
)->lyricssize
;
2005 *maxasc_p
= fontascent(lyricsfont
, lyricssize
) * Staffscale
;
2006 *maxdes_p
= fontdescent(lyricsfont
, lyricssize
) * Staffscale
;
2009 * Find the farthest any syllable ascends and descends from the
2010 * baseline of the verse. Start with the standard amount for this font
2011 * size. If the loop finds any weird syllable with bigger characters
2012 * embedded, they will be increased.
2014 for (mainll_p
= start_p
->next
; mainll_p
!= 0 && mainll_p
->str
2015 != S_FEED
; mainll_p
= mainll_p
->next
) {
2017 if (mainll_p
->str
!= S_STAFF
||
2018 mainll_p
->u
.staff_p
->staffno
!= s
)
2021 /* found a STAFF of the number we're dealing with */
2022 staff_p
= mainll_p
->u
.staff_p
;
2025 * See if this verse is present in this staff,
2026 * and if so, loop through it.
2028 for (k
= 0; k
< staff_p
->nsyllists
; k
++) {
2030 if (staff_p
->sylplace
[k
] == place
&&
2031 staff_p
->syls_p
[k
]->vno
== v
) {
2033 for (gs_p
= staff_p
->syls_p
[k
]; gs_p
!= 0;
2034 gs_p
= gs_p
->next
) {
2036 * If asc or des is greater
2037 * for this syl, save it.
2039 asc
= strascent(gs_p
->syl
);
2041 des
= strdescent(gs_p
->syl
);
2043 if (asc
> *maxasc_p
)
2045 if (des
> *maxdes_p
)
2049 /* no need to look any more */
2053 } /* for every MLL stucture in score */
2057 * Name: setsylvert()
2059 * Abstract: Set the maximum ascent and descent for a verse on a score.
2063 * Description: This function, using the given baseline, sets the relative
2064 * vertical coords of each syllable in the verse on this score.
2065 * If there are any nonnull syllables, it calls a function to
2066 * continue underscores if need be.
2070 setsylvert(start_p
, s
, place
, v
, baseline
)
2072 struct MAINLL
*start_p
; /* FEED at the start of this score */
2073 int s
; /* staff number */
2074 int place
; /* above, below, or between? */
2075 int v
; /* verse number */
2076 double baseline
; /* baseline of a verse of syllables */
2079 struct MAINLL
*mainll_p
;/* point along main linked list */
2080 struct STAFF
*staff_p
; /* point at a staff structure */
2081 struct GRPSYL
*gs_p
; /* point at a syllable */
2082 struct MAINLL
*laststaff_p
; /* point last staff that has a syllable */
2083 struct GRPSYL
*lastgs_p
;/* point at last nonnull syllable in a verse */
2084 int k
; /* loop variable */
2088 * Loop through all these syllables as before, setting their relative
2091 lastgs_p
= 0; /* set later to last nonnull syl, if exists */
2092 laststaff_p
= 0; /* set later to staff containing lastgs_p */
2094 for (mainll_p
= start_p
->next
; mainll_p
!= 0 && mainll_p
->str
2095 != S_FEED
; mainll_p
= mainll_p
->next
) {
2097 if (mainll_p
->str
!= S_STAFF
||
2098 mainll_p
->u
.staff_p
->staffno
!= s
)
2101 /* found a STAFF of the number we're dealing with */
2102 staff_p
= mainll_p
->u
.staff_p
;
2105 * See if this verse is present in this staff,
2106 * and if so, loop through it.
2108 for (k
= 0; k
< staff_p
->nsyllists
; k
++) {
2110 if (staff_p
->sylplace
[k
] == place
&&
2111 staff_p
->syls_p
[k
]->vno
== v
) {
2113 for (gs_p
= staff_p
->syls_p
[k
]; gs_p
!= 0;
2114 gs_p
= gs_p
->next
) {
2116 if (gs_p
->syl
== 0) {
2120 gs_p
->c
[RY
] = baseline
;
2122 gs_p
->c
[RN
] = baseline
2123 + strascent(gs_p
->syl
);
2125 gs_p
->c
[RS
] = baseline
2126 - strdescent(gs_p
->syl
);
2128 /* remember last nonnull syl */
2129 if (gs_p
->syl
[0] != '\0') {
2131 laststaff_p
= mainll_p
;
2136 } /* for every MLL stucture in score */
2139 * At this point, if this score has any nonnull syllables for
2140 * this verse, lastgs_p points at the last one and laststaff_p
2141 * points at its STAFF. If that last syllable ends in '_' or
2142 * '-', we may need to continue this character onto the next
2143 * score, so call a function to do that.
2145 if (lastgs_p
!= 0 && has_extender(lastgs_p
->syl
))
2146 cont_extender(laststaff_p
, place
, v
);
2152 * Abstract: Set a rectangle for pedal marks, if there are any.
2156 * Description: This function puts a rectangle into rectab for pedal marks, if
2157 * there are any on this score. It also sets their relative
2158 * vertical coordinates.
2164 struct MAINLL
*start_p
; /* FEED at the start of this score */
2165 int s
; /* staff number */
2168 struct MAINLL
*mainll_p
; /* loop through main linked list */
2169 struct STUFF
*stuff_p
; /* point along a STUFF list */
2170 float protrude
; /* farthest protrusion of rectangle */
2171 float lowpoint
; /* the lowest any mark goes */
2172 float asc
; /* ascent of a pedal mark */
2173 float hi
; /* height of a pedal mark */
2174 int k
; /* loop variable */
2177 debug(32, "dopedal file=%s line=%d s=%d", start_p
->inputfile
,
2178 start_p
->inputlineno
, s
);
2180 * Find the greatest protrusion of any currently existing rectangle.
2183 for (k
= 0; k
< reclim
; k
++) {
2184 if (rectab
[k
].s
< protrude
)
2185 protrude
= rectab
[k
].s
;
2191 * Loop through this score's part of the MLL. Whenever we find a
2192 * structure for this staff (another measure), loop through its
2193 * STUFF list, setting coords for each pedal mark.
2195 for (mainll_p
= start_p
->next
; mainll_p
!= 0 &&
2196 mainll_p
->str
!= S_FEED
; mainll_p
= mainll_p
->next
) {
2198 if (mainll_p
->str
!= S_STAFF
||
2199 mainll_p
->u
.staff_p
->staffno
!= s
)
2202 for (stuff_p
= mainll_p
->u
.staff_p
->stuff_p
;
2203 stuff_p
!= 0; stuff_p
= stuff_p
->next
) {
2205 if (stuff_p
->stuff_type
!= ST_PEDAL
)
2209 * Whichever pedal character this is, always use
2210 * C_BEGPED if pedstyle is P_LINE and the "Ped." string
2211 * for the other cases. For the former, all three
2212 * characters are the same height; and for the latter,
2213 * this string is taller than the "*". This also
2214 * handles the pedal continuation situation.
2216 stuff_p
->c
[RN
] = protrude
;
2217 if (svpath(s
, PEDSTYLE
)->pedstyle
== P_LINE
) {
2218 asc
= ascent(FONT_MUSIC
, DFLT_SIZE
, C_BEGPED
);
2219 hi
= height(FONT_MUSIC
, DFLT_SIZE
, C_BEGPED
);
2220 } else { /* P_PEDSTAR or P_ALTPEDSTAR */
2221 asc
= strascent(Ped_start
);
2222 hi
= strheight(Ped_start
);
2225 asc
*= Score
.staffscale
;
2226 hi
*= Score
.staffscale
;
2231 stuff_p
->c
[RY
] = protrude
- asc
;
2232 stuff_p
->c
[RS
] = protrude
- hi
;
2234 if (stuff_p
->c
[RS
] < lowpoint
)
2235 lowpoint
= stuff_p
->c
[RS
];
2240 * If we found pedal mark(s), put one big rectangle in rectab, spanning
2241 * the width of the page.
2244 rectab
[reclim
].n
= protrude
;
2245 rectab
[reclim
].s
= lowpoint
;
2246 rectab
[reclim
].w
= 0;
2247 rectab
[reclim
].e
= PGWIDTH
;
2256 * Abstract: Set up rectangles and vert coords for ending marks.
2260 * Description: This function puts into rectab rectangles for ending marks.
2261 * Also, MARKCOORD structures get linked to BARs for them.
2265 doendings(start_p
, s
)
2267 struct MAINLL
*start_p
; /* FEED at the start of this score */
2268 int s
; /* staff number */
2271 struct MAINLL
*mainll_p
;/* point along main linked list */
2272 struct BAR
*bar_p
; /* point at a bar or pseudobar on this score */
2275 debug(32, "doendings file=%s line=%d s=%d", start_p
->inputfile
,
2276 start_p
->inputlineno
, s
);
2277 /* if endings are not to be drawn over this staff, get out */
2278 if (has_ending(s
) == NO
)
2281 /* point at pseudobar in clefsig that immediately follows this feed */
2282 mainll_p
= start_p
->next
;
2283 bar_p
= mainll_p
->u
.clefsig_p
->bar_p
;
2286 * If an ending starts at the pseudobar, or is continuing on from the
2287 * previous score, handle it, along with any following continguous ones.
2289 if (bar_p
->endingloc
!= NOITEM
) {
2291 * Search forward for the end of this ending (or following
2292 * contiguous ones), or the end of the score, whichever comes
2295 while ( ! (mainll_p
->str
== S_BAR
&&
2296 mainll_p
->u
.bar_p
->endingloc
== ENDITEM
)
2297 && mainll_p
->str
!= S_FEED
) {
2299 mainll_p
= mainll_p
->next
;
2302 /* handle ending(s) from start to this bar or feed */
2303 storeend(start_p
, mainll_p
, s
);
2305 /* if feed, there's nothing more to look for */
2306 if (mainll_p
->str
== S_FEED
)
2309 /* point after this bar at end of this ending(s) */
2310 mainll_p
= mainll_p
->next
;
2314 * Search the rest of the score for contiguous groups of endings.
2316 while (mainll_p
!= 0 && mainll_p
->str
!= S_FEED
) {
2318 /* find another bar; return if there aren't any more */
2319 while (mainll_p
!= 0 && mainll_p
->str
!= S_BAR
&&
2320 mainll_p
->str
!= S_FEED
)
2321 mainll_p
= mainll_p
->next
;
2322 if (mainll_p
== 0 || mainll_p
->str
== S_FEED
)
2326 * We found another bar. If it isn't associated with an
2327 * ending, point beyond it and continue to go look for the
2330 if (mainll_p
->u
.bar_p
->endingloc
== NOITEM
) {
2331 mainll_p
= mainll_p
->next
;
2336 * This bar is the start of an ending. Search forward for the
2337 * end of this ending (or following contiguous ones), or the
2338 * end of the score, whichever comes first.
2341 while ( ! (mainll_p
->str
== S_BAR
&&
2342 mainll_p
->u
.bar_p
->endingloc
== ENDITEM
)
2343 && mainll_p
->str
!= S_FEED
) {
2345 mainll_p
= mainll_p
->next
;
2348 /* handle ending(s) from start to this bar or feed */
2349 storeend(start_p
, mainll_p
, s
);
2351 /* if feed, there's nothing more to look for */
2352 if (mainll_p
->str
== S_FEED
)
2355 /* point after this bar at end of this ending */
2356 mainll_p
= mainll_p
->next
;
2363 * Abstract: Set up rectangles and vert coords for contiguous endings.
2367 * Description: This function is given the starting and ending bars of a group
2368 * of continguous ending marks on a staff. The starting "bar"
2369 * may be the pseudobar at the start of the score; and the ending
2370 * bar may be the end of the score. This function applies stackit
2371 * to them as a unit. It adds another rectangle to rectab to
2372 * prevent anything later from getting in between the ending(s)
2373 * and the staff. Then, for the starting bar of each ending in
2374 * the group, it allocates a MARKCOORD structure.
2378 storeend(start_p
, end_p
, s
)
2380 struct MAINLL
*start_p
; /* the start of these ending(s) */
2381 struct MAINLL
*end_p
; /* the end of these ending(s) */
2382 int s
; /* staff number */
2385 struct MAINLL
*mainll_p
;/* point along main linked list */
2386 struct BAR
*bar_p
; /* point at a bar or pseudobar on this score */
2387 struct MARKCOORD
*mark_p
; /* we allocate these for bars to point at */
2388 float west
, east
; /* extremities of group of ending(s) */
2389 float south
; /* their bottom boundary */
2393 * Find the west and east boundaries of the ending(s).
2395 if (start_p
->str
== S_FEED
)
2396 west
= start_p
->next
->u
.clefsig_p
->bar_p
->c
[AX
]; /* pseudobar */
2398 west
= start_p
->u
.bar_p
->c
[AX
]; /* normal bar */
2400 if (end_p
->str
== S_FEED
)
2401 east
= PGWIDTH
- eff_rightmargin(end_p
); /* end of score */
2403 east
= end_p
->u
.bar_p
->c
[AX
]; /* normal bar */
2405 /* make a rectangle out of the ending(s) and find where they go */
2406 south
= stackit(west
, east
, ENDINGHEIGHT
, (double)0.0, PL_ABOVE
);
2409 * Superimpose another rectangle on top of the one stackit put there;
2410 * one that reaches down to the staff. This ensures that nothing later
2411 * will get between the ending(s) and the staff.
2413 rectab
[reclim
].n
= south
+ ENDINGHEIGHT
;
2414 rectab
[reclim
].s
= 0;
2415 rectab
[reclim
].e
= east
;
2416 rectab
[reclim
].w
= west
;
2420 * If the pseudobar has an ending, calloc a markcoord structure and put
2421 * it in the pseudobar's linked list of them.
2423 if (start_p
->str
== S_FEED
) {
2424 bar_p
= start_p
->next
->u
.clefsig_p
->bar_p
;
2425 CALLOC(MARKCOORD
, mark_p
, 1);
2426 mark_p
->next
= bar_p
->ending_p
;
2427 bar_p
->ending_p
= mark_p
;
2428 mark_p
->staffno
= (short)s
;
2433 * Loop through this part of the score. Wherever there is a bar that
2434 * is the start of an ending, calloc a markcoord structure and put it
2435 * in the bar's linked list of them.
2437 for (mainll_p
= start_p
; mainll_p
!= end_p
; mainll_p
= mainll_p
->next
) {
2438 if (mainll_p
->str
!= S_BAR
)
2440 bar_p
= mainll_p
->u
.bar_p
;
2441 if (bar_p
->endingloc
!= STARTITEM
)
2443 CALLOC(MARKCOORD
, mark_p
, 1);
2444 mark_p
->next
= bar_p
->ending_p
;
2445 bar_p
->ending_p
= mark_p
;
2446 mark_p
->staffno
= (short)s
;
2454 * Abstract: Set up rectangles and vert coords for rehearsal marks.
2458 * Description: This function puts into rectab rectangles for rehearsal marks.
2459 * Also, MARKCOORD structures get linked to BARs for them.
2463 dorehears(start_p
, s
)
2465 struct MAINLL
*start_p
; /* FEED at the start of this score */
2466 int s
; /* staff number */
2469 struct MAINLL
*mainll_p
;/* point along main linked list */
2470 struct BAR
*bar_p
; /* point at a bar or pseudobar on this score */
2471 struct MARKCOORD
*mark_p
; /* we allocate these for bars to point at */
2472 float west
, east
; /* of a rehearsal mark */
2473 float south
; /* of a rehearsal mark */
2474 float height
; /* of a rehearsal mark */
2475 float dist
; /* distance from center of staff */
2476 int dopseudo
; /* do the pseudobar's rehearsal mark? */
2477 char *reh_string
; /* string for the reh mark */
2480 debug(32, "dorehears file=%s line=%d s=%d", start_p
->inputfile
,
2481 start_p
->inputlineno
, s
);
2482 /* if rehearsal marks are not to be drawn over this staff, get out */
2483 if (has_ending(s
) == NO
)
2486 /* point at pseudobar in clefsig that immediately follows this feed */
2487 mainll_p
= start_p
->next
;
2488 bar_p
= mainll_p
->u
.clefsig_p
->bar_p
;
2490 /* if there's a rehearsal mark at the pseudobar, note that fact */
2491 if (bar_p
->reh_type
!= REH_NONE
)
2497 * Loop through the score, dealing with the pseudobar (if it has a
2498 * rehearsal mark), and all real bars that have a rehearsal mark.
2500 for ( ; mainll_p
!= 0 && mainll_p
->str
!= S_FEED
;
2501 mainll_p
= mainll_p
->next
) {
2503 if (dopseudo
== YES
|| mainll_p
->str
== S_BAR
&&
2504 mainll_p
->u
.bar_p
->reh_type
!= REH_NONE
){
2505 if (dopseudo
== YES
)
2508 bar_p
= mainll_p
->u
.bar_p
;
2511 * Find the size of the rehearsal label, including 6
2512 * more points to allow for the box around it. Make
2513 * its first character be centered over the bar line.
2514 * Place it by using stackit.
2516 reh_string
= get_reh_string(bar_p
->reh_string
, s
);
2517 height
= strheight(reh_string
);
2518 west
= bar_p
->c
[AX
] - left_width(reh_string
);
2519 east
= west
+ strwidth(reh_string
);
2521 if (bar_p
->dist_usage
== SD_NONE
) {
2522 /* get the usual dist */
2523 dist
= svpath(s
, DIST
)->dist
;
2525 /* override with this bar's dist */
2528 /* convert to inches from center of staff */
2529 dist
= halfstaffhi(s
) + STEPSIZE
* dist
;
2531 if (bar_p
->dist_usage
== SD_FORCE
) {
2533 * The user is forcing this dist, so don't
2534 * stack; just put it there.
2537 rectab
[reclim
].n
= south
+ height
;
2538 rectab
[reclim
].s
= south
;
2539 rectab
[reclim
].e
= east
;
2540 rectab
[reclim
].w
= west
;
2543 /* stack the usual way */
2544 south
= stackit(west
, east
, height
, dist
,
2549 * Allocate and link a MARKCOORD, and put the necessary
2552 CALLOC(MARKCOORD
, mark_p
, 1);
2553 mark_p
->next
= bar_p
->reh_p
;
2554 bar_p
->reh_p
= mark_p
;
2555 mark_p
->staffno
= (short)s
;
2556 mark_p
->ry
= south
+ strdescent(reh_string
);
2564 * Abstract: Place a rectangle and add it to rectab.
2566 * Returns: south boundary of the new rectangle
2568 * Description: This function puts the given rectangle into rectab. It is put
2569 * as close to the staff or baseline as is possible without
2570 * overlapping rectangles already in rectab, and without letting
2571 * it get any closer to the staff/baseline than "dist" STEPSIZE.
2575 stackit(west
, east
, height
, dist
, place
)
2577 double west
; /* west edge of the new rectangle */
2578 double east
; /* east edge of the new rectangle */
2579 double height
; /* height of the new rectangle */
2580 double dist
; /* min dist from item to center line of staff*/
2581 int place
; /* above, below, or between? */
2584 float north
, south
; /* trial boundaries for new rectangle */
2585 int try; /* which element of rectab to try */
2586 int overlap
; /* does our rectangle overlap existing ones? */
2587 int j
; /* loop variable */
2591 * For each rectangle in rectab, decide whether (based on
2592 * its horizontal coords) it could possibly overlap with our
2593 * new rectangle. If it's totally left or right of ours, it
2594 * can't. We allow a slight overlap (FUDGE) so that round
2595 * off errors don't stop us from packing things as tightly
2598 for (j
= 0; j
< reclim
; j
++) {
2599 if (rectab
[j
].w
+ FUDGE
> east
||
2600 rectab
[j
].e
< west
+ FUDGE
)
2601 rectab
[j
].relevant
= NO
;
2603 rectab
[j
].relevant
= YES
;
2607 * Set up first trial position for this rectangle: "dist" inches
2608 * away from the center line of the staff. For "between", it always
2609 * starts at the baseline.
2611 north
= south
= 0.0; /* prevent useless 'used before set' warning */
2614 /* work downward from staff, allowing "dist" distance */
2616 south
= north
- height
;
2619 /* work upward from staff, allowing "dist" distance */
2621 north
= south
+ height
;
2624 /* work upward from baseline */
2631 * Mark the "tried" field for all relevant rectangles. This says
2632 * whether we have already tried using their boundaries for positioning
2633 * our rectangle. Any rectangle that is closer to the staff/baseline
2634 * than we want to allow, we mark as if we have tried it already.
2636 for (j
= 0; j
< reclim
; j
++) {
2637 if (rectab
[j
].relevant
== YES
) {
2638 if (place
== PL_BELOW
&& rectab
[j
].s
> north
||
2639 place
!= PL_BELOW
&& rectab
[j
].n
< south
)
2640 rectab
[j
].tried
= YES
;
2642 rectab
[j
].tried
= NO
;
2647 * Keep trying positions for this rectangle, working outwards from the
2648 * first trial position. When we find one that doesn't overlap an
2649 * existing rectangle, break. This has to succeed at some point, at
2650 * at the outermost rectangle position if not earlier.
2654 for (j
= 0; j
< reclim
; j
++) {
2655 /* ignore ones too far east or west */
2656 if (rectab
[j
].relevant
== NO
)
2659 /* if all south or north, okay; else overlap */
2660 if (rectab
[j
].s
+ FUDGE
<= north
&&
2661 rectab
[j
].n
>= south
+ FUDGE
) {
2667 /* if no rectangle overlapped, we found a valid place */
2672 * Something overlapped, so we have to try again. Find the
2673 * innermost relevant outer rectangle boundary that hasn't been
2674 * tried already, to use as the next trial position for our
2675 * rectangle's inner boundary.
2678 for (j
= 0; j
< reclim
; j
++) {
2679 /* ignore ones too far east or west */
2680 if (rectab
[j
].relevant
== NO
|| rectab
[j
].tried
== YES
)
2684 * If this is the first relevant one we haven't tried,
2685 * or if this is farther in than the innermost so far,
2686 * save it as being the new innermost so far.
2688 if (place
== PL_BELOW
) {
2689 if (try == -1 || rectab
[j
].s
> rectab
[try].s
)
2692 if (try == -1 || rectab
[j
].n
< rectab
[try].n
)
2698 pfatal("bug in stackit()");
2701 * Mark this one as having been tried (for next time around, if
2702 * necessary). Set new trial values for north and south of our
2705 rectab
[try].tried
= YES
;
2706 if (place
== PL_BELOW
) {
2707 north
= rectab
[try].s
;
2708 south
= north
- height
;
2710 south
= rectab
[try].n
;
2711 north
= south
+ height
;
2714 } /* end of while loop trying positions for this rectangle */
2717 * We found the correct position for the new rectangle. Enter it
2720 rectab
[reclim
].n
= north
;
2721 rectab
[reclim
].s
= south
;
2722 rectab
[reclim
].e
= east
;
2723 rectab
[reclim
].w
= west
;
2731 * Name: inc_reclim()
2733 * Abstract: Increment no. of rectangles, and realloc more if we run out.
2737 * Description: This function increments reclim, the index into rectab. If it
2738 * finds that rectab[reclim] is now beyond the end of the space
2739 * that's been allocated, it does a realloc to get more space.
2745 /* when first called, relvert will have allocated this many */
2746 static int rectabsize
= RECTCHUNK
;
2751 /* if rectab[reclim] is still valid, no need to allocate more */
2752 if (reclim
< rectabsize
)
2755 /* must allocate another chunk of rectangles */
2756 rectabsize
+= RECTCHUNK
;
2757 REALLOC(RECTAB
, rectab
, rectabsize
);