chiark / gitweb /
Import upstream version 5.3.
[mup] / mup / mup / restsyl.c
CommitLineData
69695f33
MW
1/* Copyright (c) 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005 by Arkkra Enterprises */
2/* All rights reserved */
3/*
4 * Name: restsyl.c
5 *
6 * Description: This file contains functions for setting the relative
7 * horizontal and vertical coordinates of all groups that
8 * contain a rest or space (grpcont != GC_NOTES), and the relative
9 * horizontal coordinates of syllables. It then completes
10 * the relative horizontal work by setting the relative
11 * horizontal coords of chords. But before it does that last
12 * step, it scales all the relative coords set so far according
13 * to staffscale.
14 */
15
16#include "defines.h"
17#include "structs.h"
18#include "globals.h"
19
20#define PK_LEFT (0)
21#define PK_RIGHT (1)
22#define PK_CENTER (2)
23#define PK_NONE (3)
24
25static double highcoord P((struct GRPSYL *gs_p, struct GRPSYL *altgs_p));
26static double lowcoord P((struct GRPSYL *gs_p, struct GRPSYL *altgs_p));
27static void procrests P((struct CHORD *ch_p, struct STAFF *staff_p,
28 struct GRPSYL *gs_p, double limhigh, double limlow));
29static void procspaces P((struct GRPSYL *gs_p));
30static struct GRPSYL *finalgroupproc P((struct GRPSYL *gs1_p));
31static int v3pack P((struct GRPSYL *g_p[], int numgrps));
32static void fixclef P((struct GRPSYL *gs1_p));
33static void restsize P((struct GRPSYL *gs_p, float *wid_p, float *asc_p,
34 float *des_p));
35static void procsyls P((struct GRPSYL *gs_p));
36static void apply_staffscale P((void));
37static void relxchord P((void));
38static double effwest P((struct MAINLL *mainll_p, struct CHORD *ch_p,
39 struct GRPSYL *gs_p));
40static double effeast P((struct CHORD *ch_p, struct GRPSYL *gs_p));
41static int collision_danger P((struct GRPSYL *g1_p, struct GRPSYL *g2_p));
42static struct CHORD *prevchord P((struct MAINLL *mainll_p, struct CHORD *ch_p));
43static struct GRPSYL *nextchsyl P((struct GRPSYL *gs_p, struct CHORD *ch_p));
44static struct GRPSYL *prevchsyl P((struct GRPSYL *gs_p,
45 struct CHORD *prevch_p));
46static void pedalroom P((void));
47static struct CHORD *closestchord P((double count, struct CHORD *firstch_p));
48static double rightped P((int pedstyle, int pedchar));
49static double leftped P((int pedstyle, int pedchar));
50static void fixspace P((void));
51\f
52/*
53 * Name: restsyl()
54 *
55 * Abstract: Sets all relative coords for rests and spaces, and horizontal
56 * ones for syllables; set relative horz. coords of chords.
57 *
58 * Returns: void
59 *
60 * Description: This function loops through the main linked list, finding every
61 * STAFF structure. For groups, it calls procrests() to process
62 * every rest in the linked list, and procspaces() to process
63 * every space in the linked list. For syllables, it calls
64 * procsyls(). At the end it calls apply_staffscale() to apply
65 * staffscale to all the relative coords set so far, and then
66 * relxchord() to set the relative horizontal coords of chords.
67 */
68
69void
70restsyl()
71
72{
73 register struct MAINLL *mainll_p; /* point item in main linked list */
74 struct MAINLL *mll_p; /* another MLL pointer */
75 struct STAFF *staff_p; /* point at a staff */
76 struct STAFF *stafflist[MAXSTAFFS + 1]; /* point to this meas's staffs*/
77 float limhigh[MAXSTAFFS + 1]; /* high y coord of limit of groups */
78 float limlow[MAXSTAFFS + 1]; /* low y coord of limit of groups */
79 int vscheme; /* voice scheme */
80 int v; /* index into verse headcell array */
81 struct CHORD *ch_p; /* point at a chord */
82 struct GRPSYL *gs1_p; /* point at a group */
83
84
85 debug(16, "restsyl");
86 initstructs();
87
88
89 /*
90 * Loop down the main linked list looking for each chord list
91 * headcell.
92 */
93 for (mainll_p = Mainllhc_p; mainll_p != 0; mainll_p = mainll_p->next) {
94
95 if (mainll_p->str == S_SSV) {
96 asgnssv(mainll_p->u.ssv_p);
97 continue;
98 }
99
100 if (mainll_p->str != S_CHHEAD)
101 continue; /* skip everything but chord HC */
102
103 /*
104 * For each visible staff in this measure, find the high and
105 * low limits of the relevant voices, so that we know what to
106 * avoid when placing rests in other voices.
107 */
108 for (mll_p = mainll_p->next; mll_p->str == S_STAFF;
109 mll_p = mll_p->next) {
110
111 staff_p = mll_p->u.staff_p;
112 stafflist[staff_p->staffno] = staff_p;
113 vscheme = svpath(staff_p->staffno, VSCHEME)->vscheme;
114 if (staff_p->visible == NO) {
115 continue;
116 }
117
118 /*
119 * If there is more than one voice, each voice's rests
120 * have to worry about avoiding other voices' notes.
121 * So find how high voice 2 and how low voice 1, get,
122 * in this measure. But voice 3 can "stand in" for
123 * either, so pass that in too. If it's null, that's
124 * okay, the subroutines handle that.
125 */
126 if (vscheme != V_1) {
127 limhigh[staff_p->staffno] =
128 highcoord(staff_p->groups_p[1],
129 staff_p->groups_p[2]);
130 limlow[staff_p->staffno] =
131 lowcoord(staff_p->groups_p[0],
132 staff_p->groups_p[2]);
133 } else {
134 /* prevent uninitialized var, though not used*/
135 limhigh[staff_p->staffno] = 0;
136 limlow[staff_p->staffno] = 0;
137 }
138 }
139
140 /*
141 * Loop through each chord in this list.
142 */
143 for (ch_p = mainll_p->u.chhead_p->ch_p; ch_p != 0;
144 ch_p = ch_p->ch_p) {
145 /*
146 * Loop through the linked list of GRPSYLs hanging off
147 * this chord. Skip the syllables; just deal with the
148 * groups. Upon finding the first group on a staff
149 * (which could be for any of the voices, since not all
150 * might be present in this chord), call procrests and
151 * finalgroupproc to process the groups.
152 */
153 gs1_p = ch_p->gs_p;
154 for (;;) {
155 /* find first group on a staff */
156 while (gs1_p != 0 &&
157 gs1_p->grpsyl == GS_SYLLABLE)
158 gs1_p = gs1_p->gs_p;
159 if (gs1_p == 0)
160 break;
161
162 /*
163 * Call procrests() to place any rest in the
164 * voice on this staff in this chord.
165 */
166 procrests(ch_p, stafflist[gs1_p->staffno],
167 gs1_p, limhigh[gs1_p->staffno],
168 limlow[gs1_p->staffno]);
169
170 /* set gs1_p to after this staff's groups */
171 gs1_p = finalgroupproc(gs1_p);
172 }
173 }
174 }
175
176 initstructs();
177
178 /*
179 * Loop once for each item in the main linked list. Now that we're all
180 * done with notes and rests, do the spaces and syllables.
181 */
182 for (mainll_p = Mainllhc_p; mainll_p != 0; mainll_p = mainll_p->next) {
183
184 if (mainll_p->str == S_SSV) {
185
186 asgnssv(mainll_p->u.ssv_p);
187
188 } else if (mainll_p->str == S_STAFF &&
189 mainll_p->u.staff_p->visible == YES) {
190
191 /* for each voice that exists, process the spaces */
192 for (v = 0; v < MAXVOICES; v++) {
193 if (mainll_p->u.staff_p->groups_p[v] != 0) {
194 procspaces(mainll_p->u.staff_p->
195 groups_p[v]);
196 }
197 }
198
199 /* set relative horizontal coords for syllables */
200 for (v = 0; v < mainll_p->u.staff_p->nsyllists; v++) {
201 procsyls(mainll_p->u.staff_p->syls_p[v]);
202 }
203 }
204 }
205
206 /* scale all relative coords set so far according to staffscale */
207 apply_staffscale();
208
209 /* now we are ready to set relative horizontal coords for all chords */
210 relxchord();
211}
212\f
213/*
214 * Name: highcoord()
215 *
216 * Abstract: Find highest relative y coord of a group in one GRPSYL list.
217 *
218 * Returns: void
219 *
220 * Description: This function goes down one of the linked lists of GRPSYLs,
221 * one that is for groups, not syllables, and finds the highest
222 * relative y coordinate of any group containing notes. If there
223 * are no notes but there are rests, it returns 0. If there are
224 * only spaces, it returns -100. The answer, though, is rounded
225 * off to the nearest staff line. Besides the primary linked list
226 * of GRPSYLs, it also looks for GRPSYLs in the alternate list
227 * (voice 3 if it exists) and considers ones that are "standing in"
228 * for the first list's voice.
229 */
230
231static double
232highcoord(gs_p, altgs_p)
233
234register struct GRPSYL *gs_p; /* starts pointing at first GRPSYL in list */
235register struct GRPSYL *altgs_p;/* first GRPSYL of voice 3, if any */
236
237{
238 float result;
239 int normvoice; /* main voice we are dealing with, 1 or 2 */
240 float edge; /* of a group in the other voice */
241
242
243 debug(32, "highcoord file=%s line=%d", gs_p->inputfile,
244 gs_p->inputlineno);
245 result = -100; /* init as if only spaces */
246 normvoice = gs_p->vno; /* remember the voice we're dealing with */
247
248 /*
249 * Loop through all groups (even grace), moving result up when
250 * something higher is found. Rests count as 0 (the middle line).
251 */
252 for ( ; gs_p != 0; gs_p = gs_p->next) {
253 switch (gs_p->grpcont) {
254 case GC_NOTES:
255 edge = gs_p->c[RN];
256 /* if wrong way stem, account for it as best we can */
257 if (gs_p->stemdir == UP) {
258 edge += (stemroom(gs_p) - 1.0) * STEPSIZE;
259 }
260 if (edge > result) {
261 result = edge;
262 }
263 break;
264 case GC_REST:
265 if (result < 0)
266 result = 0;
267 break;
268 /* ignore spaces */
269 }
270 }
271
272 /*
273 * Look at every GRPSYL in voice 3, if any. If it is "standing in" for
274 * the normal voice, move result up if need be.
275 */
276 for ( ; altgs_p != 0; altgs_p = altgs_p->next) {
277 if (altgs_p->pvno == normvoice) {
278 switch (altgs_p->grpcont) {
279 case GC_NOTES:
280 if (altgs_p->c[RN] > result)
281 result = altgs_p->c[RN];
282 break;
283 case GC_REST:
284 if (result < 0)
285 result = 0;
286 break;
287 /* ignore spaces */
288 }
289 }
290 }
291
292 return (nearestline(result));
293}
294\f
295/*
296 * Name: lowcoord()
297 *
298 * Abstract: Find lowest relative y coord of a group in one GRPSYL list.
299 *
300 * Returns: void
301 *
302 * Description: This function goes down one of the linked lists of GRPSYLs,
303 * one that is for groups, not syllables, and finds the lowest
304 * relative y coordinate of any group containing notes. If there
305 * are no notes but there are rests, it returns 0. If there are
306 * only spaces, it returns 100. The answer, though, is rounded
307 * off to the nearest staff line. Besides the primary linked list
308 * of GRPSYLs, it also looks for GRPSYLs in the alternate list
309 * (voice 3 if it exists) and considers ones that are "standing in"
310 * for the first list's voice.
311 */
312
313static double
314lowcoord(gs_p, altgs_p)
315
316register struct GRPSYL *gs_p; /* starts pointing at first GRPSYL in list */
317register struct GRPSYL *altgs_p;/* first GRPSYL of voice 3, if any */
318
319{
320 float result;
321 int normvoice; /* main voice we are dealing with, 1 or 2 */
322 float edge; /* of a group in the other voice */
323
324
325 debug(32, "lowcoord file=%s line=%d", gs_p->inputfile,
326 gs_p->inputlineno);
327 result = 100; /* init as if only spaces */
328 normvoice = gs_p->vno; /* remember the voice we're dealing with */
329
330 /*
331 * Loop through all groups (even grace), moving result down when
332 * something lower is found. Rests count as 0 (the middle line).
333 */
334 for ( ; gs_p != 0; gs_p = gs_p->next) {
335 switch (gs_p->grpcont) {
336 case GC_NOTES:
337 edge = gs_p->c[RS];
338 /* if wrong way stem, account for it as best we can */
339 if (gs_p->stemdir == DOWN) {
340 edge -= (stemroom(gs_p) - 1.0) * STEPSIZE;
341 }
342 if (edge < result) {
343 result = edge;
344 }
345 break;
346 case GC_REST:
347 if (result > 0)
348 result = 0;
349 break;
350 /* ignore spaces */
351 }
352 }
353
354 /*
355 * Look at every GRPSYL in voice 3, if any. If it is "standing in" for
356 * the normal voice, move result up if need be.
357 */
358 for ( ; altgs_p != 0; altgs_p = altgs_p->next) {
359 if (altgs_p->pvno == normvoice) {
360 switch (altgs_p->grpcont) {
361 case GC_NOTES:
362 if (altgs_p->c[RS] < result)
363 result = altgs_p->c[RS];
364 break;
365 case GC_REST:
366 if (result > 0)
367 result = 0;
368 break;
369 /* ignore spaces */
370 }
371 }
372 }
373
374 return (nearestline(result));
375}
376\f
377/*
378 * Name: procrests()
379 *
380 * Abstract: Sets relative coordinates for rests in one CHORD/STAFF.
381 *
382 * Returns: void
383 *
384 * Description: This function is given the top GRPSYL on a STAFF in a CHORD.
385 * It sets the relative coordinates of each rest GRPSYL on this
386 * STAFF/CHORD.
387 */
388
389static void
390procrests(ch_p, staff_p, gs1_p, limhigh, limlow)
391
392struct CHORD *ch_p; /* the chord we are in */
393struct STAFF *staff_p; /* the staff we are processing */
394struct GRPSYL *gs1_p; /* point at top GRPSYL in chord */
395double limhigh; /* highest relative y coord below v1 */
396double limlow; /* lowest relative y coord above v2 */
397
398{
399 RATIONAL endtime; /* time at the end of the rest */
400 struct GRPSYL *g_p[MAXVOICES + 1]; /* index by vno, point at GRPSYL */
401 struct GRPSYL *gs_p; /* a GRPSYL we are now working on */
402 struct GRPSYL *ogs_p; /* other voice to be considered */
403 float wid, asc, des; /* width, ascent, and descent of a rest */
404 int vscheme; /* voice scheme */
405 int restsabove; /* are these rests above another voice? */
406 int stafflines; /* no. of lines in staff */
407 int v; /* voice number */
408 float y; /* relative y coord for this rest */
409
410
411 debug(32, "procrests file=%s line=%d limhigh=%f limlow=%f",
412 gs1_p->inputfile, gs1_p->inputlineno,
413 (float)limhigh, (float)limlow);
414
415
416 /* get voice scheme and number of lines in staff */
417 vscheme = svpath(gs1_p->staffno, VSCHEME)->vscheme;
418 stafflines = svpath(gs1_p->staffno, STAFFLINES)->stafflines;
419
420 /* set pointers to all nonspace groups in this chord on this staff */
421 for (v = 1; v <= MAXVOICES; v++) {
422 g_p[v] = 0;
423 }
424 for (gs_p = gs1_p; gs_p != 0 && gs_p->staffno == gs1_p->staffno &&
425 gs_p->grpsyl == GS_GROUP; gs_p = gs_p->gs_p) {
426 if (gs_p->grpcont != GC_SPACE) {
427 g_p[gs_p->vno] = gs_p;
428 }
429 }
430
431 y = 0.0; /* to avoid useless 'used before set' warning */
432 ogs_p = 0; /* to avoid useless 'used before set' warning */
433
434 /*
435 * Loop through each possible voice, setting its coords if it is a rest.
436 */
437 for (v = 1; v <= MAXVOICES; v++) {
438
439 gs_p = g_p[v];
440
441 if (gs_p == 0 || gs_p->grpcont != GC_REST) {
442 continue;
443 }
444
445 /* find the time at the end of the rest */
446 endtime = radd(ch_p->starttime, gs_p->fulltime);
447
448 /* find width, ascent, and descent of the rest */
449 restsize(gs_p, &wid, &asc, &des);
450
451 /*
452 * Find out if another voice needs to be considered in the
453 * placement of this rest, and set ogs_p to that voice's first
454 * GRPSYL if so.
455 */
456 ogs_p = 0;
457 if (vscheme == V_2FREESTEM ||
458 vscheme == V_3FREESTEM && gs_p->pvno != 3) {
459 ogs_p = gs_p->pvno == 1 ? staff_p->groups_p[1] :
460 staff_p->groups_p[0];
461 }
462
463 /*
464 * Find the RY of the rest.
465 */
466 if (vscheme == V_1 || (vscheme == V_2FREESTEM ||
467 vscheme == V_3FREESTEM) &&
468 hasspace(ogs_p, ch_p->starttime, endtime)) {
469 /*
470 * There is either only 1 voice, or we are 2f/3f and the
471 * other voice is all spaces during this time. Usually
472 * RY should be 0. But for one-line staffs, whole
473 * rest characters need to be lowered so that they hang
474 * under the line.
475 */
476 if (stafflines == 1 && gs_p->basictime == 1) {
477 y = -2 * STEPSIZE;
478 } else {
479 y = 0;
480 }
481 } else {
482 /*
483 * We are 2o, or 2f/3f with notes/rests in the other
484 * voice that we must avoid hitting. Set up the
485 * relative y coord, based on whether gs_p is acting
486 * as v1 or v2. We also have to set up restsabove
487 * for use below.
488 */
489 restsabove = NO; /* default value for now */
490 switch (gs_p->pvno) {
491 case 1:
492 y = limhigh < -4 * STEPSIZE ?
493 0 : limhigh + 4 * STEPSIZE;
494 restsabove = ! hasspace(staff_p->groups_p[1],
495 Zero, Maxtime);
496 /* also check for v3 groups acting as v2 */
497 for (ogs_p = staff_p->groups_p[2];
498 ogs_p != 0 && restsabove == NO;
499 ogs_p = ogs_p->next) {
500 if (ogs_p->pvno == 2 &&
501 ogs_p->grpcont != GC_SPACE) {
502 restsabove = YES;
503 break;
504 }
505 }
506 break;
507 case 2:
508 y = limlow > 4 * STEPSIZE ?
509 0 : limlow - 4 * STEPSIZE;
510 break;
511 }
512
513 /*
514 * Usually RY should be the y was set above. But
515 * if this is the upper voice, half rests and longer
516 * should be lower to fall within the staff when
517 * feasible, since they don't take much space
518 * vertically and we don't want needless ledger lines.
519 * (But nothing should ever be lowered if already on
520 * the center line.) Short rests need to be moved
521 * away from the other voice by varying amounts,
522 * depending on how tall they are. Quad whole rests
523 * below need to be raised a notch.
524 */
525 if (restsabove == YES) {
526 /* lower whole & double only if above middle */
527 if (gs_p->basictime <= 2 && y > 0)
528 y -= 2 * STEPSIZE;
529 if (gs_p->basictime >= 16)
530 y += 2 * STEPSIZE;
531 if (gs_p->basictime == 256)
532 y += 2 * STEPSIZE;
533 } else {
534 if (gs_p->basictime >= 128)
535 y -= 2 * STEPSIZE;
536 if (gs_p->basictime == -1)
537 y += 2 * STEPSIZE;
538 }
539 }
540
541 /*
542 * If restdist was set by the user, use that instead of
543 * whatever we calculated above.
544 */
545 if (gs_p->restdist != NORESTDIST) {
546 y = gs_p->restdist * STEPSIZE;
547 }
548
549 /* set all the relative coords */
550 gs_p->c[RX] = 0;
551 gs_p->c[RE] = wid / 2;
552 gs_p->c[RW] = -wid / 2 - gs_p->padding -
553 vvpath(gs_p->staffno, gs_p->vno, PAD)->pad;
554 gs_p->c[RY] = y;
555 gs_p->c[RN] = y + asc;
556 gs_p->c[RS] = y - des;
557
558 /* if there are dot(s), add their widths to the east side */
559 if (gs_p->dots > 0) {
560 gs_p->c[RE] += gs_p->dots * (width(FONT_MUSIC,
561 DFLT_SIZE, C_DOT) + 2 * STDPAD);
562 }
563 }
564}
565\f
566/*
567 * Name: procspaces()
568 *
569 * Abstract: Sets relative coordinates for spaces in one GRPSYL list.
570 *
571 * Returns: void
572 *
573 * Description: This function goes down one of the linked lists of GRPSYLs,
574 * one that is for groups, not syllables, and sets the relative
575 * coordinates for each space found. Usually these coords will
576 * be left as 0, the way they were calloc'ed, but not when there
577 * is padding or uncompressible spaces.
578 */
579
580static void
581procspaces(gs_p)
582
583register struct GRPSYL *gs_p; /* starts pointing at first GRPSYL in list */
584
585{
586 static float half_us_width; /* half width of uncompressible space*/
587 char headchar; /* char representing a note head */
588 int headfont; /* music font for head char */
589
590
591 /*
592 * Loop, setting all relative coords of spaces, except that if they are
593 * to be zero there's no need to set them, since calloc zeroed them.
594 * The vertical ones are always zero, and so is RX.
595 */
596 for ( ; gs_p != 0; gs_p = gs_p->next) {
597 if (gs_p->grpcont != GC_SPACE)
598 continue;
599
600 if (gs_p->uncompressible == YES) {
601 /*
602 * If this is the first time in here, set this to half
603 * a blank quarter note head plus standard pad.
604 */
605 if (half_us_width == 0.0) {
606 headchar = nheadchar(get_shape_num("blank"),
607 4, UP, &headfont);
608 half_us_width = width(headfont, DFLT_SIZE,
609 headchar) / 2.0 + STDPAD;
610 }
611
612 /* center the imaginary note head */
613 gs_p->c[RE] = half_us_width / 2;
614 gs_p->c[RW] = -half_us_width / 2;
615
616 /* apply global user requested padding; notice that
617 * normal spaces (s) don't get this */
618 gs_p->c[RW] -= vvpath(gs_p->staffno,
619 gs_p->vno, PAD)->pad;
620 }
621
622 /* add any user requested padding */
623 gs_p->c[RW] -= gs_p->padding;
624 }
625}
626\f
627/*
628 * Name: finalgroupproc()
629 *
630 * Abstract: Do final processing of groups.
631 *
632 * Returns: pointer to the first GRPSYL after these groups, 0 if none
633 *
634 * Description: This function is given the GRPSYL for the first (topmost) voice
635 * that is on this staff in this chord. It find what other
636 * GRPSYLs exist. For all the nonspace groups, it applies any
637 * horizontal offsets needed.
638 */
639
640static struct GRPSYL *
641finalgroupproc(gs1_p)
642
643struct GRPSYL *gs1_p; /* first voice on this staff in this chord */
644
645{
646 struct GRPSYL *g_p[MAXVOICES]; /* point at nonspace voices' groups */
647 struct GRPSYL *gs_p; /* point at groups in the chord */
648 struct GRPSYL *last_p; /* point at last nonspace group */
649 int numgrps; /* how many nonspace groups are here */
650 int staffno; /* staff these groups are on */
651 int n; /* loop variable */
652 float offset; /* of each when + and - are used */
653 float edge; /* west or east coord of group 1 or 2 */
654 int pack; /* optimization for voice 3 */
655
656
657 staffno = gs1_p->staffno; /* remember staffno of first group */
658 numgrps = 0; /* no groups found yet */
659 last_p = 0; /* no last nonspace group yet */
660
661 /* find all groups in this chord on this staff; remember nonspaces */
662 for (gs_p = gs1_p; gs_p != 0 && gs_p->staffno == staffno &&
663 gs_p->grpsyl == GS_GROUP; gs_p = gs_p->gs_p) {
664 if (gs_p->grpcont != GC_SPACE) {
665 g_p[numgrps++] = gs_p;
666 last_p = gs_p;
667 }
668 }
669
670 /*
671 * If all groups on this staff were spaces, just make sure clef is
672 * marked correctly and return, though it's unlikely we have a clef
673 * change before a space.
674 */
675 if (numgrps == 0) {
676 fixclef(gs1_p);
677 return (gs_p);
678 }
679
680 /* nothing to do for tab, since "ho" is ignored and rests invisible */
681 if (is_tab_staff(g_p[0]->staffno))
682 return (gs_p);
683
684 /* for any voice with a user supplied offset value, apply it now */
685 for (n = 0; n < numgrps; n++) {
686 if (g_p[n]->ho_usage == HO_VALUE)
687 shiftgs(g_p[n], g_p[n]->ho_value * STEPSIZE);
688 }
689
690 /*
691 * If both voices 1 and 2 are nonspace, handle any ho "+" or "-".
692 */
693 if (numgrps >= 2 && g_p[0]->vno == 1 && g_p[1]->vno == 2) {
694 /*
695 * Verify and fix offsets. We did this in setgrps.c for note
696 * groups so that compatible note groups could then be handled
697 * together. But we need to check again in case rest groups
698 * are involved.
699 */
700 vfyoffset(g_p);
701
702 /*
703 * Check each of these 2 groups: If it has "+" or "-" and the
704 * other one doesn't, shift it to be next to the other one on
705 * the appropriate side.
706 */
707 for (n = 0; n < 2; n++) {
708 if ((g_p[n]->ho_usage == HO_LEFT ||
709 g_p[n]->ho_usage == HO_RIGHT) &&
710 ! (g_p[1-n]->ho_usage == HO_LEFT ||
711 g_p[1-n]->ho_usage == HO_RIGHT)) {
712
713 if (g_p[n]->ho_usage == HO_LEFT) {
714 shiftgs(g_p[n],
715 g_p[1-n]->c[RW] - g_p[n]->c[RE]);
716 } else {
717 shiftgs(g_p[n],
718 g_p[1-n]->c[RE] - g_p[n]->c[RW]);
719 }
720 }
721 }
722
723 /*
724 * If one has "+" and one has "-", shift them each by half of
725 * the amount of space needed to avoid a collision.
726 */
727 if (g_p[0]->ho_usage == HO_LEFT &&
728 g_p[1]->ho_usage == HO_RIGHT) {
729
730 offset = (g_p[0]->c[RE] - g_p[1]->c[RW]) / 2.0;
731 shiftgs(g_p[0], -offset);
732 shiftgs(g_p[1], offset);
733 }
734 if (g_p[0]->ho_usage == HO_RIGHT &&
735 g_p[1]->ho_usage == HO_LEFT) {
736
737 offset = (g_p[1]->c[RE] - g_p[0]->c[RW]) / 2.0;
738 shiftgs(g_p[0], offset);
739 shiftgs(g_p[1], -offset);
740 }
741
742 } else if (g_p[0]->vno != 3) {
743 /*
744 * If only one of groups 1 and 2 is nonspace, check whether it
745 * has "+" or "-", and warn if so.
746 */
747 if (g_p[0]->ho_usage == HO_LEFT || g_p[0]->ho_usage == HO_RIGHT)
748 {
749 l_warning(
750 g_p[0]->inputfile, g_p[0]->inputlineno,
751 "voice %d cannot have horizontal offset '%c' since voice %d is not present; ignoring it",
752 g_p[0]->vno,
753 g_p[0]->ho_usage == HO_LEFT ? '-' :'+',
754 3 - g_p[0]->vno);
755
756 g_p[0]->ho_usage = HO_NONE;
757 }
758 }
759
760 /*
761 * If voice 3 and at least one other voice exist here, and the user
762 * didn't state an offset value for voice 3, offset it next to the
763 * other voices, on the left or right, as requested. But exclude the
764 * case where voice 3 was being treated as 1 or 2, by checking pvno
765 * instead of vno.
766 */
767 if (numgrps > 1 && last_p->pvno == 3 && last_p->ho_usage != HO_VALUE) {
768 /*
769 * See if we can pack v3 tightly against v1 and v2. (This will
770 * not be allowed if ho_usage != HO_NONE for any voice, or any
771 * other of many conditions doesn't hold true.)
772 */
773 pack = v3pack(g_p, numgrps);
774 if (pack != PK_NONE) {
775 /*
776 * Yes, we can; shift v3 a little if necessary. Make
777 * it so that v3's stem is one stepsize away from the
778 * group that its stem is pointing toward.
779 */
780 switch (pack) {
781 case PK_LEFT:
782 /* since v3 is on left, v2 must exist, and is
783 * the voice preceding v3 in g_p */
784 shiftgs(last_p, -STEPSIZE +
785 widest_head(last_p) / 2.0 +
786 g_p[numgrps-2]->c[RW]);
787 break;
788 case PK_RIGHT:
789 /* since v3 is on right, v1 must exist, and is
790 * the first voice in g_p */
791 shiftgs(last_p, STEPSIZE +
792 g_p[0]->c[RE] -
793 widest_head(last_p) / 2.0);
794 break;
795 /* for PK_CENTER, nothing to do */
796 }
797
798 } else if (last_p->ho_usage == HO_LEFT) {
799
800 /* find leftmost edge of the other voice(s) */
801 edge = g_p[0]->c[RW];
802 for (n = 1; n < numgrps - 1; n++) {
803 if (g_p[n]->c[RW] < edge)
804 edge = g_p[n]->c[RW];
805 }
806 /* set right edge of voice 3 == left edge of others */
807 shiftgs(last_p, edge - last_p->c[RE]);
808
809 } else { /* HO_RIGHT, or HO_NONE which defaults to HO_RIGHT */
810
811 /* find rightmost edge of the other voice(s) */
812 edge = g_p[0]->c[RE];
813 for (n = 1; n < numgrps - 1; n++) {
814 if (g_p[n]->c[RE] > edge)
815 edge = g_p[n]->c[RE];
816 }
817 /* set left edge of voice 3 == right edge of others */
818 shiftgs(last_p, edge - last_p->c[RW]);
819 }
820 } else if (g_p[0]->vno == 3 && (g_p[0]->ho_usage == HO_LEFT ||
821 g_p[0]->ho_usage == HO_RIGHT)) {
822 /*
823 * If the first (and thus only) voice is 3, it should not have
824 * ho "+" or "-".
825 */
826 l_warning(
827 g_p[0]->inputfile, g_p[0]->inputlineno,
828 "voice 3 cannot have horizontal offset '%c' since voices 1 and 2 are not present; ignoring it",
829 g_p[0]->ho_usage == HO_LEFT ? '-' :'+');
830
831 g_p[0]->ho_usage = HO_NONE;
832 }
833
834 /* in case of midmeasure clef change, make sure it's marked right */
835 fixclef(gs1_p);
836
837 /* return the first GRPSYL after the groups we processed */
838 return (gs_p);
839}
840\f
841/*
842 * Name: v3pack()
843 *
844 * Abstract: Decide whether v3 can be packed tighter than the default.
845 *
846 * Returns: PK_NONE no, it can't
847 * PK_LEFT pack tightly on left
848 * PK_RIGHT pack tightly on right
849 * PK_CENTER pack in the center
850 *
851 * Description: This function decides whether the voice 3 group can be packed
852 * in more tightly against voices 1 and 2 than the usual default
853 * of just putting v3's group's rectangle to the right of the
854 * other voices. If there seems to be any danger that v3 would
855 * collide with v1 or v2, it gives up and returns PK_NONE. It
856 * could be made a lot more sophisticated and not give up so soon
857 * in many cases. However many of these improvements can't be
858 * done very well at this stage of the game, where we don't know
859 * yet about stem lengths, beam positions, etc.
860 */
861
862static int
863v3pack(g_p, numgrps)
864
865struct GRPSYL *g_p[]; /* point at nonspace voices' groups */
866int numgrps; /* how many nonspace groups are here */
867
868{
869 struct GRPSYL *gs_p; /* point at a group */
870 struct GRPSYL *v3_p; /* point at v3's group */
871 struct NOTE *v3note_p; /* v3 note that neighbors other voice*/
872 struct NOTE *onote_p; /* v1/v2 note that neighbors v3 */
873 float north; /* highest coord of note or acc */
874 float south; /* lowest coord of note or acc */
875 float topdesc; /* descent of acc of top group */
876 float botasc; /* ascent of acc of bottom group */
877 int v3hasacc, otherhasacc; /* do v3 and other voice have acc(s)?*/
878 int pack;
879 int n; /* loop variable */
880 int k; /* loop variable */
881
882
883 /* either v1 or v2 must be nonspace */
884 if (numgrps == 1) {
885 return (PK_NONE);
886 }
887
888 /* point at v3's group for convenience */
889 v3_p = g_p[numgrps - 1];
890
891 /* set up what the answer will be if we can apply the optimization */
892 if (v3_p->basictime >= 2) {
893 /* there is a stem, so offset such that stem will avoid v1/v2 */
894 if (v3_p->stemdir == UP) {
895 pack = PK_RIGHT;
896 } else { /* DOWN */
897 pack = PK_LEFT;
898 }
899 } else {
900 pack = PK_CENTER; /* no stem, so we can center v3 */
901 }
902
903 /* v3 must not be standing in for v1 or v2 */
904 if (v3_p->pvno != 3) {
905 return (PK_NONE);
906 }
907
908 /* if v3 would be on left, it must not have a flag or be start of beam*/
909 if (pack == PK_LEFT && (v3_p->basictime >= 8 && v3_p->beamloc == NOITEM
910 || v3_p->beamloc == STARTITEM)) {
911 return (PK_NONE);
912 }
913
914 /* if v3 would be on right, it must not have grace groups preceding */
915 if (pack == PK_RIGHT && v3_p->prev != 0 &&
916 v3_p->prev->grpvalue == GV_ZERO) {
917 return (PK_NONE);
918 }
919
920 /* v3 cannot have slashes or alternation */
921 if (v3_p->slash_alt != 0) {
922 return (PK_NONE);
923 }
924
925 /*
926 * Loop through all voices, checking for rule violations. We do it
927 * in reverse so that we know v3 is notes (the first check) before
928 * checking the other voices.
929 */
930 for (n = numgrps - 1; n >= 0; n--) {
931 gs_p = g_p[n]; /* set to current voice for convenience */
932
933 /* voice must be notes, and not measure repeat */
934 if (gs_p->grpcont != GC_NOTES || gs_p->is_meas) {
935 return (PK_NONE);
936 }
937
938 /* voice cannot have user requested horizontal offset */
939 if (gs_p->ho_usage != HO_NONE) {
940 return (PK_NONE);
941 }
942
943 /* voice cannot have a "with" list */
944 if (gs_p->nwith != 0) {
945 return (PK_NONE);
946 }
947
948 /* voice cannot have a roll */
949 if (gs_p->roll != NOITEM) {
950 return (PK_NONE);
951 }
952
953 /* do voice specific checks */
954 switch (gs_p->vno) {
955
956 case 1:
957 /* stem must be up */
958 if (gs_p->stemdir != UP) {
959 return (PK_NONE);
960 }
961
962 /* find neighboring notes of v1 and v3 */
963 v3note_p = &v3_p->notelist[0];
964 onote_p = &gs_p->notelist[gs_p->nnotes - 1];
965
966 /* neighboring notes in v1 & v3 must not be too close */
967 if (onote_p->stepsup < v3note_p->stepsup + 2 ||
968 onote_p->stepsup == v3note_p->stepsup + 2 &&
969 pack != PK_CENTER &&
970 (v3_p->basictime < 1 || gs_p->basictime < 1)) {
971 return (PK_NONE);
972 }
973
974 /* if 2 steps apart and on lines and v3 would not be on
975 * right, v1 can't have dots and v3 can't unless it
976 * is on the right */
977 if (onote_p->stepsup == v3note_p->stepsup + 2 &&
978 EVEN(v3note_p->stepsup) &&
979 (gs_p->dots != 0 ||
980 pack != PK_RIGHT && v3_p->dots != 0)) {
981 return (PK_NONE);
982 }
983
984 /*
985 * Find the lowest extension of any accidental in v1.
986 * If no accidentals, the initial value for "south"
987 * will remain. It's not good enough to check accs
988 * only on the neighboring notes, because some of them
989 * stick out pretty far. We have to go through these
990 * gyrations because group boundaries do not consider
991 * accidentals that stick out up or down.
992 */
993 otherhasacc = NO;
994 south = onote_p->c[RY] - STEPSIZE + 0.001;
995 for (k = 0; k < gs_p->nnotes; k++) {
996 accdimen(&gs_p->notelist[k], (float *)0,
997 &topdesc, (float *)0);
998 if (gs_p->notelist[k].c[RY] - topdesc < south) {
999 south = gs_p->notelist[k].c[RY]
1000 - topdesc;
1001 }
1002 if (gs_p->notelist[k].accidental != '\0') {
1003 otherhasacc = YES;
1004 }
1005 }
1006 /* similarly, find highest extension of v3 accs */
1007 v3hasacc = NO;
1008 north = v3note_p->c[RY] + STEPSIZE - 0.001;
1009 for (k = 0; k < v3_p->nnotes; k++) {
1010 accdimen(&v3_p->notelist[k], &botasc,
1011 (float *)0, (float *)0);
1012 if (v3_p->notelist[k].c[RY] + botasc > north) {
1013 north = v3_p->notelist[k].c[RY]
1014 + botasc;
1015 }
1016 if (v3_p->notelist[k].accidental != '\0') {
1017 v3hasacc = YES;
1018 }
1019 }
1020 /* if v1 and v3 overlap due to acc(s), fail */
1021 if (south < north) {
1022 switch (pack) {
1023 case PK_RIGHT:
1024 if (v3hasacc == YES) {
1025 return (PK_NONE);
1026 }
1027 break;
1028 case PK_CENTER:
1029 if (v3hasacc == YES &&
1030 otherhasacc == YES) {
1031 return (PK_NONE);
1032 }
1033 break;
1034 case PK_LEFT:
1035 if (otherhasacc == YES) {
1036 return (PK_NONE);
1037 }
1038 break;
1039 }
1040 }
1041
1042 /* if left or right offset, neighboring notes in v1 &
1043 * v3 must not have parentheses when accs exist */
1044 if ((pack != PK_CENTER || v3hasacc == YES || otherhasacc == YES) &&
1045 (v3note_p->note_has_paren || onote_p->note_has_paren)) {
1046 return (PK_NONE);
1047 }
1048
1049 break;
1050
1051 case 2:
1052 if (gs_p->stemdir != DOWN) {
1053 return (PK_NONE);
1054 }
1055
1056 /* find neighboring notes of v2 and v3 */
1057 v3note_p = &v3_p->notelist[v3_p->nnotes - 1];
1058 onote_p = &gs_p->notelist[0];
1059
1060 /* neighboring notes in v1 & v3 must not be too close */
1061 if (onote_p->stepsup > v3note_p->stepsup - 2 ||
1062 onote_p->stepsup == v3note_p->stepsup - 2 &&
1063 pack != PK_CENTER &&
1064 (v3_p->basictime < 1 || gs_p->basictime < 1)) {
1065 return (PK_NONE);
1066 }
1067
1068 /* if 2 steps apart and on lines and v3 would not be on
1069 * right, neither can have dots */
1070 if (onote_p->stepsup == v3note_p->stepsup - 2 &&
1071 EVEN(v3note_p->stepsup) &&
1072 pack != PK_RIGHT &&
1073 (gs_p->dots != 0 || v3_p->dots != 0)) {
1074 return (PK_NONE);
1075 }
1076
1077 /*
1078 * Find the highest extension of any accidental in v2.
1079 * If no accidentals, the initial value for "north"
1080 * will remain.
1081 */
1082 otherhasacc = NO;
1083 north = onote_p->c[RY] + STEPSIZE - 0.001;
1084 for (k = 0; k < gs_p->nnotes; k++) {
1085 accdimen(&gs_p->notelist[k], &botasc,
1086 (float *)0, (float *)0);
1087 if (gs_p->notelist[k].c[RY] + botasc > north) {
1088 north = gs_p->notelist[k].c[RY]
1089 + botasc;
1090 }
1091 if (gs_p->notelist[k].accidental != '\0') {
1092 otherhasacc = YES;
1093 }
1094 }
1095 /* similarly, find highest extension of v3 accs */
1096 v3hasacc = NO;
1097 south = v3note_p->c[RY] - STEPSIZE + 0.001;
1098 for (k = 0; k < v3_p->nnotes; k++) {
1099 accdimen(&v3_p->notelist[k], (float *)0,
1100 &topdesc, (float *)0);
1101 if (v3_p->notelist[k].c[RY] - topdesc < south) {
1102 south = v3_p->notelist[k].c[RY]
1103 - topdesc;
1104 }
1105 if (v3_p->notelist[k].accidental != '\0') {
1106 v3hasacc = YES;
1107 }
1108 }
1109 /* if v2 and v3 overlap due to acc(s), fail */
1110 if (south < north) {
1111 switch (pack) {
1112 case PK_RIGHT:
1113 if (v3hasacc == YES) {
1114 return (PK_NONE);
1115 }
1116 break;
1117 case PK_CENTER:
1118 if (v3hasacc == YES &&
1119 otherhasacc == YES) {
1120 return (PK_NONE);
1121 }
1122 if (v3hasacc == YES &&
1123 gs_p->nnotes >= 2 &&
1124 onote_p->stepsup ==
1125 gs_p->notelist[1].stepsup + 1) {
1126 return (PK_NONE);
1127 }
1128 break;
1129 case PK_LEFT:
1130 if (otherhasacc == YES) {
1131 return (PK_NONE);
1132 }
1133 break;
1134 }
1135 }
1136
1137 /* if left or right offset, neighboring notes in v2 &
1138 * v3 must not have parentheses when accs exist */
1139 if ((pack != PK_CENTER || v3hasacc == YES || otherhasacc == YES) &&
1140 (v3note_p->note_has_paren || onote_p->note_has_paren)) {
1141 return (PK_NONE);
1142 }
1143
1144 break;
1145 }
1146 }
1147
1148 /* all checks passed, so return the answer */
1149 return (pack);
1150}
1151\f
1152/*
1153 * Name: fixclef()
1154 *
1155 * Abstract: If midmeasure clef change at this chord, mark in right GRPSYL.
1156 *
1157 * Returns: void
1158 *
1159 * Description: This function is given the GRPSYL for the first (topmost) voice
1160 * that is on this staff in this chord. If the clef changed at
1161 * this time value, locllnotes() in setnotes.c will have set the
1162 * "clef" field in each of the GRPSYLs in this chord on this
1163 * staff (actually in their first preceding grace group, if
1164 * any). But it should only be set in the GRPSYL that has the
1165 * westernmost west boundary. So this function erases it from
1166 * any other GRPSYLs.
1167 */
1168
1169static void
1170fixclef(gs1_p)
1171
1172struct GRPSYL *gs1_p; /* starts at first voice on this staff */
1173
1174{
1175 struct GRPSYL *g_p[MAXVOICES]; /* point at voices' groups */
1176 struct GRPSYL *gs_p; /* point at groups in the chord */
1177 int numgrps; /* how many groups are in the chord */
1178 struct GRPSYL *westgs_p; /* remember westernmost */
1179 int staffno; /* staff number */
1180 int n; /* loop variable */
1181
1182
1183 staffno = gs1_p->staffno; /* remember staffno of first group */
1184
1185 /* point at all groups in this chord on this staff */
1186 numgrps = 0; /* no groups found yet */
1187 for (gs_p = gs1_p; gs_p != 0 && gs_p->staffno == staffno &&
1188 gs_p->grpsyl == GS_GROUP; gs_p = gs_p->gs_p) {
1189 g_p[numgrps++] = gs_p;
1190 }
1191
1192 /*
1193 * For each that is preceded by grace group(s), change the pointer to
1194 * point at the first in that sequence of grace groups. Any clef
1195 * change would occur at that group.
1196 */
1197 for (n = 0; n < numgrps; n++) {
1198 while (g_p[n]->prev != 0 && g_p[n]->prev->grpvalue == GV_ZERO) {
1199 g_p[n] = g_p[n]->prev;
1200 }
1201 }
1202
1203 /* if clef not marked in first, it's not marked in any, so return */
1204 if (g_p[0]->clef == NOCLEF) {
1205 return;
1206 }
1207
1208 westgs_p = 0; /* prevent useless "used before set" warning */
1209
1210 /*
1211 * Find the westernmost group of notes, if any; if it's a tie, use the
1212 * first one. We don't want to put clefs in front of rests, spaces, or
1213 * mrpt, unless we have no choice.
1214 */
1215 for (n = 0; n < numgrps; n++) {
1216 if (g_p[n]->grpcont == GC_NOTES && g_p[n]->is_meas == NO) {
1217 if (westgs_p == 0 || g_p[n]->c[RW] < westgs_p->c[RW]) {
1218 westgs_p = g_p[n];
1219 }
1220 }
1221 }
1222 /* we have no choice; arbitrarily choose the first voice */
1223 if (westgs_p == NULL) {
1224 westgs_p = g_p[0];
1225 }
1226
1227 /* erase clef from all but the group found above */
1228 for (n = 0; n < numgrps; n++) {
1229 if (g_p[n] != westgs_p) {
1230 g_p[n]->clef = NOCLEF;
1231 }
1232 }
1233
1234 /* if there were no notes, there will be no clef here */
1235 if (westgs_p == 0) {
1236 return;
1237 }
1238
1239 /* move western boundary of GRPSYL to allow room to print the clef */
1240 westgs_p->c[RW] -= clefwidth(westgs_p->clef, YES) + CLEFPAD;
1241
1242 /*
1243 * If this is a grace group, we also have to alter its main group's
1244 * boundary, because the main group's boundary needs to enclose all
1245 * its grace groups.
1246 */
1247 for (gs_p = westgs_p; gs_p->grpvalue == GV_ZERO; gs_p = gs_p->next) {
1248 ;
1249 }
1250 if (gs_p != westgs_p) {
1251 gs_p->c[RW] -= clefwidth(westgs_p->clef, YES) + CLEFPAD;
1252 }
1253}
1254\f
1255/*
1256 * Name: restsize()
1257 *
1258 * Abstract: Find the size of a rest.
1259 *
1260 * Returns: void
1261 *
1262 * Description: This function is given a GRPSYL which is a rest. It returns
1263 * the width, ascent, and descent through pointers.
1264 */
1265
1266static void
1267restsize(gs_p, wid_p, asc_p, des_p)
1268
1269register struct GRPSYL *gs_p; /* the GRPSYL containing the rest */
1270float *wid_p, *asc_p, *des_p; /* return width, ascent, and descent of rest */
1271
1272{
1273 char rchar; /* char for the rest */
1274 int size; /* font size */
1275
1276
1277 /* multirest has no music character; just return the answer */
1278 if (gs_p->basictime < -1) {
1279 *wid_p = MINMULTIWIDTH;
1280 *asc_p = 2 * STEPSIZE;
1281 *des_p = 2 * STEPSIZE;
1282 return;
1283 }
1284
1285 /* on a tab staff rests are invisible, so set to a very small size */
1286 if (is_tab_staff(gs_p->staffno)) {
1287 *wid_p = *asc_p = *des_p = 0.01;
1288 return;
1289 }
1290
1291 /*
1292 * The "normal" rest case. Find the name of the character. Then get
1293 * the width, ascent, and descent of the rest.
1294 */
1295 rchar = restchar(gs_p->basictime);
1296 size = (gs_p->grpsize == GS_NORMAL ? DFLT_SIZE : SMALLSIZE);
1297 *wid_p = width(FONT_MUSIC, size, rchar);
1298 *asc_p = ascent(FONT_MUSIC, size, rchar);
1299 *des_p = descent(FONT_MUSIC, size, rchar);
1300}
1301\f
1302/*
1303 * Name: procsyls()
1304 *
1305 * Abstract: Sets relative horizontal coords for syllables in 1 GRPSYL list.
1306 *
1307 * Returns: void
1308 *
1309 * Description: This function goes down one of the linked lists of GRPSYLs,
1310 * one that is for syllables, not groups, and sets the relative
1311 * horizontal coordinates for each syllable found.
1312 */
1313
1314static void
1315procsyls(gs_p)
1316
1317register struct GRPSYL *gs_p; /* starts pointing at first GRPSYL in list */
1318
1319{
1320 float wid_b4_syl; /* width of leading non-lyrics */
1321 float wid_real_syl; /* width of actual lyric */
1322 float wid_after_syl; /* width of trailing non-lyrics */
1323 float lyricsalign; /* fraction of syl to go left of chord center*/
1324 int font, size; /* of the last char in a syllable */
1325 char lc; /* last char of syllable */
1326
1327
1328 debug(32, "procsyls file=%s line=%d", gs_p->inputfile,
1329 gs_p->inputlineno);
1330 /* find what fraction of each syl should go left of center of chord */
1331 lyricsalign = svpath(gs_p->staffno, LYRICSALIGN)->lyricsalign;
1332
1333 /*
1334 * Set coords for every syllable. A syllable can consist of 3 parts.
1335 * The middle part is the actual lyric. The optional first and last
1336 * parts are surrounded in the user's input by angle brackets. The
1337 * syllable is to be positioned such that "lyricsalign" of the middle
1338 * part goes to the left of the chord's center, and the rest goes to
1339 * the right; unless sylposition is set, in which case the left edge of
1340 * the actual lyric is offset by that many points from the chord's
1341 * center. Then adjust the east side for padding purposes.
1342 */
1343 for ( ; gs_p != 0; gs_p = gs_p->next) {
1344 sylwidth(gs_p->syl, &wid_b4_syl, &wid_real_syl, &wid_after_syl);
1345
1346 gs_p->c[RX] = 0;
1347 if (gs_p->sylposition == NOSYLPOSITION) {
1348 gs_p->c[RW] = -lyricsalign * wid_real_syl - wid_b4_syl;
1349 gs_p->c[RE] = (1 - lyricsalign) * wid_real_syl +
1350 wid_after_syl;
1351 } else {
1352 gs_p->c[RW] = gs_p->sylposition * POINT - wid_b4_syl;
1353 gs_p->c[RE] = gs_p->sylposition * POINT + wid_real_syl +
1354 wid_after_syl;
1355 }
1356
1357 /* get last char of syl; if null syl don't alter RE any more */
1358 lc = last_char(gs_p->syl);
1359 if (lc == '\0')
1360 continue;
1361
1362 /*
1363 * If this is not the last syllable of the measure, and it
1364 * doesn't end in '-', leave space for a blank after it, to
1365 * separate it from the next syllable.
1366 */
1367 if ( gs_p->next != 0 && lc != '-') {
1368 end_fontsize(gs_p->syl, &font, &size);
1369 gs_p->c[RE] += width(font, size, ' ');
1370 }
1371
1372 /*
1373 * If this is the last syllable of the measure, and it ends in
1374 * '-', back up a space, letting the '-' go into the bar line.
1375 */
1376 if ( gs_p->next == 0 && lc == '-' ) {
1377 end_fontsize(gs_p->syl, &font, &size);
1378 gs_p->c[RE] -= width(font, size, ' ');
1379 }
1380 }
1381}
1382\f
1383/*
1384 * Name: apply_staffscale()
1385 *
1386 * Abstract: Scale all relative coordinates according to staffscale.
1387 *
1388 * Returns: void
1389 *
1390 * Description: Throughout Mup, we are able to almost entirely avoid dealing
1391 * with the "scale" parameter, by the following trick: We pretend
1392 * the paper is a different size than it really is, by the inverse
1393 * of the "scale" factor, place and print everything at standard
1394 * size, and then at the end apply the scale to everything at
1395 * once, in PostScript. (Margins are exempt from scaling, hence
1396 * the EFF_* macros to cancel it out.)
1397 *
1398 * But for the "staffscale" parameter, this kind of trick only
1399 * works up to a point. As long as we are dealing only with
1400 * relative coords on one staff at a time, as we have up to this
1401 * point in the program, we can ignore staffscale. But now we're
1402 * about to start dealing with chord coords, and chords span
1403 * staffs. So the jig is up.
1404 *
1405 * This function goes through all the relative coords set so far,
1406 * and scales them according to staffscale. It also scales the
1407 * font sizes in strings. From this point on staffscale must
1408 * always be considered.
1409 */
1410
1411static void
1412apply_staffscale()
1413
1414{
1415 struct MAINLL *mainll_p; /* point at items in main linked list*/
1416 struct STAFF *staff_p; /* point at a staff structure */
1417 register float staffscale; /* current staffscale */
1418 register struct GRPSYL *gs_p; /* point at groups */
1419 register struct NOTE *note_p; /* point at notes */
1420 struct STUFF *stuff_p; /* point at a stuff structure */
1421 int n; /* loop variable */
1422 int v; /* voice number, 0 to 2 */
1423
1424
1425 debug(16, "apply_staffscale");
1426
1427 initstructs();
1428
1429 /*
1430 * Loop down the main linked list looking for each staff.
1431 */
1432 for (mainll_p = Mainllhc_p; mainll_p != 0; mainll_p = mainll_p->next) {
1433
1434 switch (mainll_p->str) {
1435 case S_SSV:
1436 /* apply SSVs to keep staffscale up to date */
1437 asgnssv(mainll_p->u.ssv_p);
1438 continue;
1439
1440 case S_STAFF:
1441 staff_p = mainll_p->u.staff_p;
1442 break; /* break out to handle staffs */
1443
1444 default:
1445 continue; /* nothing to do */
1446 }
1447
1448 /* get staffscale for this staff in this measure */
1449 staffscale = svpath(staff_p->staffno, STAFFSCALE)->staffscale;
1450
1451 /* go through each voice this staff has */
1452 for (v = 0; v < MAXVOICES; v++) {
1453
1454 /* and each group in each voice */
1455 for (gs_p = staff_p->groups_p[v]; gs_p != 0;
1456 gs_p = gs_p->next) {
1457
1458 /* scale the group's relative coords */
1459 gs_p->c[RX] *= staffscale;
1460 gs_p->c[RN] *= staffscale;
1461 gs_p->c[RY] *= staffscale;
1462 gs_p->c[RS] *= staffscale;
1463
1464 /* but don't disturb this E,W constant value */
1465 /* (see setgrps.c and abshorz.c) */
1466 if (gs_p->c[RE] != TEMPMRPTWIDTH / 2.0) {
1467 gs_p->c[RE] *= staffscale;
1468 gs_p->c[RW] *= staffscale;
1469 }
1470
1471 gs_p->xdotr *= staffscale;
1472
1473 /* usually we're done caring about padding */
1474 /* by now, but not always, so scale it */
1475 gs_p->padding *= staffscale;
1476
1477 if (gs_p->grpcont == GC_NOTES) {
1478 for (n = 0; n < gs_p->nnotes; n++) {
1479 note_p = &gs_p->notelist[n];
1480
1481 /* scale note's rel. coords */
1482 note_p->c[RW] *= staffscale;
1483 note_p->c[RX] *= staffscale;
1484 note_p->c[RE] *= staffscale;
1485 note_p->c[RN] *= staffscale;
1486 note_p->c[RY] *= staffscale;
1487 note_p->c[RS] *= staffscale;
1488
1489 note_p->waccr *= staffscale;
1490 note_p->ydotr *= staffscale;
1491 note_p->wlparen *= staffscale;
1492 note_p->erparen *= staffscale;
1493
1494 /* this isn't really scaling,
1495 * but it's a convenient place
1496 * to undo CSS_STEPS */
1497 if (gs_p->stemto == CS_ABOVE &&
1498 n <= gs_p->stemto_idx) {
1499 gs_p->notelist[n].stepsup -= CSS_STEPS;
1500 gs_p->notelist[n].ydotr -=
1501 CSS_STEPS * STEPSIZE * staffscale;
1502 } else if (gs_p->stemto == CS_BELOW &&
1503 n >= gs_p->stemto_idx) {
1504 gs_p->notelist[n].stepsup += CSS_STEPS;
1505 gs_p->notelist[n].ydotr +=
1506 CSS_STEPS * STEPSIZE * staffscale;
1507 }
1508 }
1509 }
1510
1511 for (n = 0; n < gs_p->nwith; n++) {
1512 (void)resize_string(gs_p->withlist[n],
1513 staffscale,
1514 gs_p->inputfile,
1515 gs_p->inputlineno);
1516 }
1517 }
1518 }
1519
1520 /* scale the syllables' coords and font sizes */
1521 for (v = 0; v < staff_p->nsyllists; v++) {
1522 for (gs_p = staff_p->syls_p[v]; gs_p != 0;
1523 gs_p = gs_p->next) {
1524 gs_p->c[RW] *= staffscale;
1525 gs_p->c[RX] *= staffscale;
1526 gs_p->c[RE] *= staffscale;
1527 gs_p->c[RN] *= staffscale;
1528 gs_p->c[RY] *= staffscale;
1529 gs_p->c[RS] *= staffscale;
1530
1531 (void)resize_string(gs_p->syl, staffscale,
1532 gs_p->inputfile, gs_p->inputlineno);
1533 }
1534 }
1535
1536 /* scale the STUFF structures' font sizes */
1537 /* (their coords won't be set until we get to stuff.c) */
1538 for (stuff_p = staff_p->stuff_p; stuff_p != 0;
1539 stuff_p = stuff_p->next) {
1540 if (stuff_p->string != 0) {
1541 (void)resize_string(
1542 stuff_p->string,
1543 stuff_p->all == YES ? Score.staffscale
1544 : staffscale,
1545 stuff_p->inputfile,
1546 stuff_p->inputlineno);
1547 }
1548 }
1549 }
1550}
1551\f
1552/*
1553 * Name: relxchord()
1554 *
1555 * Abstract: Set relative horizontal coordinates of each chord.
1556 *
1557 * Returns: void
1558 *
1559 * Description: This function goes through the chord lists, and for each chord,
1560 * sets its horizontal relative coordinates, by going down the
1561 * list of GRPSYLs hanging off it.
1562 */
1563
1564static void
1565relxchord()
1566
1567{
1568 struct CHORD *ch_p; /* point at a chord */
1569 struct CHORD *pch_p; /* point at previous chord */
1570 struct CHORD *ppch_p; /* point at chord before that */
1571 struct MAINLL *mainll_p; /* point at items in main linked list*/
1572 struct GRPSYL *gs_p; /* point at groups */
1573 struct GRPSYL *nsyl_p; /* point at next syl */
1574 struct GRPSYL *psyl_p; /* point at previous syl */
1575 float stealable; /* from previous chord */
1576 float eff; /* effective coord */
1577
1578
1579 debug(16, "relxchord");
1580 initstructs();
1581
1582 /*
1583 * Loop down the main linked list looking for each chord list headcell.
1584 */
1585 for (mainll_p = Mainllhc_p; mainll_p != 0; mainll_p = mainll_p->next) {
1586
1587 /* need to keep "pad" up to date */
1588 if (mainll_p->str == S_SSV)
1589 asgnssv(mainll_p->u.ssv_p);
1590
1591 if (mainll_p->str != S_CHHEAD)
1592 continue; /* skip everything but chord HC */
1593
1594 /*
1595 * Pretend that all the chords will be jammed tightly together,
1596 * starting at absolute coordinate zero. We set absolute
1597 * coords here for the benefit of effwest(), but they will be
1598 * overwritten with their true values later in abshorz().
1599 */
1600 mainll_p->u.chhead_p->ch_p->c[AW] = 0.0; /* west of 1st chord*/
1601
1602 /*
1603 * First, loop forwards through the chord list, setting the
1604 * boundaries and widths of each chord based only on its
1605 * groups. The chord is to extend outwards just enough to
1606 * contain every group.
1607 */
1608 for (ch_p = mainll_p->u.chhead_p->ch_p; ch_p != 0;
1609 ch_p = ch_p->ch_p) {
1610
1611 /* start chord as if 0 width */
1612 ch_p->c[RX] = 0;
1613 ch_p->c[RE] = 0;
1614 ch_p->c[RW] = 0;
1615
1616 /* loop through groups, expanding chord when necessary*/
1617 for (gs_p = ch_p->gs_p; gs_p != 0; gs_p = gs_p->gs_p) {
1618 if (gs_p->grpsyl == GS_GROUP) {
1619 /*
1620 * If last chord in measure, add pad
1621 * parameter on right side of groups;
1622 * but not for collapseable spaces (s).
1623 */
1624 if (ch_p->ch_p == 0 &&
1625 (gs_p->grpcont != GC_SPACE ||
1626 gs_p->uncompressible == YES)) {
1627 gs_p->c[RE] += vvpath(gs_p->
1628 staffno, gs_p->vno, PAD)->pad *
1629 svpath(gs_p->staffno,
1630 STAFFSCALE)->staffscale;
1631 }
1632
1633 eff = effwest(mainll_p, ch_p, gs_p);
1634 if (eff < ch_p->c[RW])
1635 ch_p->c[RW] = eff;
1636 eff = effeast(ch_p, gs_p);
1637 if (eff > ch_p->c[RE])
1638 ch_p->c[RE] = eff;
1639 }
1640 }
1641
1642 /* store width; will be updated later to include syls */
1643 ch_p->width = ch_p->c[RE] - ch_p->c[RW];
1644
1645 /* set phony absolute coords for effwest() */
1646 ch_p->c[AX] = ch_p->c[AW] - ch_p->c[RW];
1647 ch_p->c[AE] = ch_p->c[AX] + ch_p->c[RE];
1648 if (ch_p->ch_p != 0)
1649 ch_p->ch_p->c[AW] = ch_p->c[AE];
1650 }
1651
1652 /*
1653 * Loop again through each chord in this list, this time
1654 * expanding chords when necessary to include eastward
1655 * extensions of syllables. Work right to left, so that when
1656 * a syllable steals space from the following chord, the
1657 * following chord has already been widened eastwards, if it
1658 * needed to be, based on its syllables.
1659 */
1660 /* find last chord in the chord LL */
1661 ch_p = mainll_p->u.chhead_p->ch_p; /* first chord */
1662 while (ch_p->ch_p != 0)
1663 ch_p = ch_p->ch_p;
1664
1665 /* loop backwards through them (too bad there's no back ptr) */
1666 for ( ; ch_p != 0; ch_p = prevchord(mainll_p, ch_p)) {
1667 /*
1668 * Loop through the linked list of GRPSYLs hanging off
1669 * this chord, altering RE when finding a syl that
1670 * sticks out farther. There is one exception to
1671 * this. If a syllable extends farther east than any
1672 * one so far, a test is made so that it can steal
1673 * space from the following chord if that chord has
1674 * no syllable there.
1675 */
1676 for (gs_p = ch_p->gs_p; gs_p != 0; gs_p = gs_p->gs_p) {
1677
1678 /* if not a syl or not sticking out east */
1679 if (gs_p->grpsyl != GS_SYLLABLE ||
1680 gs_p->c[RE] <= ch_p->c[RE])
1681 continue;
1682
1683 /* syl seems to be sticking out east */
1684
1685 /*
1686 * If this is the last chord in the measure,
1687 * the chord boundary must include the syl.
1688 */
1689 if (ch_p->ch_p == 0) {
1690 ch_p->c[RE] = gs_p->c[RE];
1691 continue;
1692 }
1693
1694 /*
1695 * The syl is sticking out east of the current
1696 * chord boundary, and this is not the last
1697 * chord in the measure. See if the next
1698 * chord contains the next syl of this verse.
1699 * If not, there's an empty space there, and
1700 * we can let the current syl steal space from
1701 * the next chord.
1702 */
1703 nsyl_p = nextchsyl(gs_p, ch_p);
1704 if (nsyl_p == 0) {
1705 /*
1706 * Next chord has no syl here. We can
1707 * steal its space. If the syl is so
1708 * long that even that isn't enough
1709 * room, we'll force the current chord
1710 * boundary far enough out to contain
1711 * the excess.
1712 */
1713 if (gs_p->c[RE] > ch_p->c[RE] +
1714 ch_p->ch_p->width) {
1715 ch_p->c[RE] = gs_p->c[RE] -
1716 ch_p->ch_p->width;
1717 }
1718 } else {
1719 /*
1720 * Next chord has a syl, so we can't
1721 * steal its space. Extend this chord.
1722 */
1723 ch_p->c[RE] = gs_p->c[RE];
1724 }
1725 }
1726
1727 /* revise width; will be revised again later */
1728 ch_p->width = ch_p->c[RE] - ch_p->c[RW];
1729
1730 } /* end of backwards loop through chords in this measure */
1731
1732 /*
1733 * Loop again through each chord in this list, this time
1734 * expanding chords when necessary to include westward
1735 * extensions of syllables. Work left to right, so that when
1736 * a syllable steals space from the preceding chord, the
1737 * preceding chord has already been widened westwards, if it
1738 * needed to be, based on its syllables.
1739 */
1740 for (ch_p = mainll_p->u.chhead_p->ch_p; ch_p != 0;
1741 ch_p = ch_p->ch_p) {
1742 /*
1743 * Loop through the linked list of GRPSYLs hanging off
1744 * this chord, altering RW when finding a syl that
1745 * sticks out farther. There is one exception to
1746 * this. If a syllable extends farther west than any
1747 * one so far, a test is made so that it can steal
1748 * space from the following chord if that chord has
1749 * no syllable there.
1750 */
1751 for (gs_p = ch_p->gs_p; gs_p != 0; gs_p = gs_p->gs_p) {
1752
1753 /* if not a syl or not sticking out west */
1754 if (gs_p->grpsyl != GS_SYLLABLE ||
1755 gs_p->c[RW] >= ch_p->c[RW])
1756 continue;
1757
1758 /* syl seems to be sticking out west */
1759
1760 /*
1761 * If this is the first chord in the measure,
1762 * the chord boundary must include the syl.
1763 */
1764 if (prevchord(mainll_p, ch_p) == 0) {
1765 ch_p->c[RW] = gs_p->c[RW];
1766 continue;
1767 }
1768
1769 /*
1770 * The syl is sticking out west of the current
1771 * chord boundary, and this is not the first
1772 * chord in the measure. See if the previous
1773 * chord contains the previous syl of this
1774 * verse, or if the one before that stole
1775 * space from it. If not, there's an empty
1776 * space there, and we can let the current syl
1777 * steal space from the previous chord. Even
1778 * if the previous chord has no syl but the one
1779 * before stole some space from it, we can use
1780 * the part of the space it didn't steal.
1781 */
1782 /* get prev chord, & prev syl in this verse */
1783 pch_p = prevchord(mainll_p, ch_p);
1784 psyl_p = prevchsyl(gs_p, pch_p);
1785
1786 if (psyl_p == 0) {
1787 /* first, assume all of the previous */
1788 /* chord's width is available */
1789 stealable = pch_p->width;
1790
1791 /*
1792 * Get the chord before the previous.
1793 * If it exists and contains a syl,
1794 * syl may already be stealing space
1795 * east of it, in which case we can
1796 * only steal what's left over.
1797 */
1798 ppch_p = prevchord(mainll_p, pch_p);
1799 if (ppch_p != 0) {
1800 psyl_p = prevchsyl(gs_p,
1801 ppch_p);
1802
1803 if (psyl_p != 0 && psyl_p->c[RE]
1804 > ppch_p->c[RE]) {
1805 stealable -= (psyl_p->
1806 c[RE] - ppch_p->c[RE]);
1807 }
1808 }
1809
1810 /*
1811 * If our syl needs more space than is
1812 * available for stealing, widen our
1813 * chord by the necessary amount.
1814 */
1815 if (gs_p->c[RW] < ch_p->c[RW] -
1816 stealable)
1817 ch_p->c[RW] = gs_p->c[RW] +
1818 stealable;
1819 } else {
1820 /*
1821 * Prev chord has a syl, so we can't
1822 * steal its space. Extend this chord.
1823 */
1824 ch_p->c[RW] = gs_p->c[RW];
1825 }
1826 }
1827
1828 /* final revision of width */
1829 ch_p->width = ch_p->c[RE] - ch_p->c[RW];
1830
1831 } /* end of forwards loop through chords in this measure */
1832
1833 } /* end of loop through each CHHEAD in main linked list */
1834
1835 pedalroom(); /* make room for "Ped." and "*" if need be */
1836
1837 fixspace(); /* set a width for certain space chords */
1838}
1839\f
1840/*
1841 * Name: effwest()
1842 *
1843 * Abstract: Find the effective west boundary of a group.
1844 *
1845 * Returns: the RW to be used for the group
1846 *
1847 * Description: This function returns an "effective" RW for the given group.
1848 * Sometimes this is just the true RW. But if the previous chord
1849 * has no groups on this staff that are in danger of colliding, we
1850 * pretend it is a smaller number, so that our group can overlap
1851 * horizonally with previous ones that have no possibly colliding
1852 * groups.
1853 */
1854
1855static double
1856effwest(mainll_p, ch_p, gs_p)
1857
1858struct MAINLL *mainll_p; /* point at MLL item for this chord */
1859struct CHORD *ch_p; /* point at this chord */
1860struct GRPSYL *gs_p; /* point at this group */
1861
1862{
1863 struct CHORD *pch_p; /* point at previous chord */
1864 struct CHORD *ech_p; /* point at earlier chord */
1865 struct GRPSYL *pgs_p; /* point a group in previous chord */
1866 float small; /* small number to be used */
1867 int found; /* found a chord with a group on our staff? */
1868 float ourax; /* tentative value for our chord's AX */
1869 float temp; /* temp variable */
1870
1871
1872 pch_p = prevchord(mainll_p, ch_p); /* find previous chord */
1873
1874 /* if we are the first chord, return our group's true RW */
1875 if (pch_p == 0)
1876 return (gs_p->c[RW]);
1877
1878 /* set default to -1.5 stepsize */
1879 small = -1.5 * STEPSIZE * svpath(gs_p->staffno, STAFFSCALE)->staffscale;
1880
1881 /* if already closer to 0 than "small", return true RW */
1882 if (gs_p->c[RW] > small)
1883 return (gs_p->c[RW]);
1884
1885 /*
1886 * Loop through the previous chord's GRPSYLs to see if it has any
1887 * groups on this staff. If so, return our true RW, if there is a
1888 * danger of collision. If there isn't a group, or it's far enough
1889 * away vertically that we know we won't collide with it, we will leave
1890 * the loop and later return a phony RW.
1891 */
1892 for (pgs_p = pch_p->gs_p; pgs_p != 0; pgs_p = pgs_p->gs_p) {
1893 /* skip cases where there can't be any interference */
1894 if (pgs_p->staffno > gs_p->staffno)
1895 break; /* nothing more could be on our staff*/
1896 if (pgs_p->staffno < gs_p->staffno)
1897 continue; /* ignore if wrong staff */
1898 if (pgs_p->grpsyl == GS_SYLLABLE)
1899 continue; /* ignore if not a group */
1900 if (collision_danger(pgs_p, gs_p) == NO)
1901 continue;
1902
1903 /* found a group that might collide, return our true RW */
1904 return (gs_p->c[RW]);
1905 }
1906
1907 /*
1908 * There is no group on our staff in the preceding chord, or at least
1909 * none that we're in danger of colliding with. We'd like to
1910 * let our group overlap into that space if necessary. But there
1911 * might be a group in some earlier chord, and if there are enough dots
1912 * on it, or enough accidentals on our group, they could still
1913 * interfere. Find the first earlier chord, looking right to left,
1914 * that has a group neighboring our group that might collide.
1915 */
1916 found = NO;
1917 for (ech_p = prevchord(mainll_p, pch_p); ech_p != 0;
1918 ech_p = prevchord(mainll_p, ech_p)) {
1919
1920 for (pgs_p = ech_p->gs_p; pgs_p != 0; pgs_p = pgs_p->gs_p) {
1921
1922 if (pgs_p->staffno > gs_p->staffno)
1923 break; /* nothing more could be on our staff*/
1924 if (pgs_p->staffno < gs_p->staffno)
1925 continue; /* ignore if wrong staff */
1926 if (pgs_p->grpsyl == GS_SYLLABLE)
1927 continue; /* ignore if not a group */
1928 if (collision_danger(pgs_p, gs_p) == NO)
1929 continue;
1930
1931 /* found a group that might collide */
1932 found = YES;
1933 break;
1934 }
1935 if (found == YES)
1936 break;
1937 }
1938
1939 if (ech_p == 0)
1940 pfatal("no preceding group in effwest()");
1941
1942 /*
1943 * Since there could be multiple voices on this staff, there could be
1944 * multiple groups on this staff in the chord we found. Loop through
1945 * each of them, keeping track of the max value our chord's AX would
1946 * have to be to keep our group from overlapping that group.
1947 */
1948 ourax = 0.0;
1949 for ( ; pgs_p != 0 && pgs_p->staffno == gs_p->staffno &&
1950 pgs_p->grpsyl == GS_GROUP; pgs_p = pgs_p->gs_p) {
1951
1952 /* ignore ones that are vertically out of the way */
1953 if (collision_danger(pgs_p, gs_p) == NO)
1954 continue;
1955
1956 temp = ech_p->c[AX] + pgs_p->c[RE] - gs_p->c[RW];
1957 if (temp > ourax)
1958 ourax = temp;
1959 }
1960
1961 /* find what that value for our AX would make our RW be */
1962 temp = ch_p->c[AW] - ourax;
1963
1964 /* return that amount, but not more than "small" */
1965 return (MIN(temp, small));
1966}
1967\f
1968/*
1969 * Name: effeast()
1970 *
1971 * Abstract: Find the effective east boundary of a group.
1972 *
1973 * Returns: the RE to be used for the group
1974 *
1975 * Description: This function returns an "effective" RE for the given group.
1976 * Sometimes this is just the true RE. But if the next chord
1977 * has no groups on this staff that are in danger of colliding, we
1978 * pretend it is a smaller number, so that our group can overlap
1979 * horizonally with the next chord. Don't worry about colliding
1980 * with a group in a later chord; effwest() will handle that when
1981 * processing that later group.
1982 */
1983
1984static double
1985effeast(ch_p, gs_p)
1986
1987struct CHORD *ch_p; /* point at this chord */
1988struct GRPSYL *gs_p; /* point at this group */
1989
1990{
1991 struct CHORD *nch_p; /* point at next chord */
1992 struct GRPSYL *ngs_p; /* point a group in next chord */
1993 float small; /* small number to be used */
1994 float onestep; /* a stepsize, scaled */
1995
1996
1997 nch_p = ch_p->ch_p; /* find next chord */
1998
1999 /* if we are the last chord, return our group's true RE */
2000 if (nch_p == 0)
2001 return (gs_p->c[RE]);
2002
2003 /* set default to 1.5 stepsize */
2004 onestep = STEPSIZE * svpath(gs_p->staffno, STAFFSCALE)->staffscale;
2005 small = 1.5 * onestep;
2006
2007 /* if already closer to 0 than "small", return true RE */
2008 if (gs_p->c[RE] < small)
2009 return (gs_p->c[RE]);
2010
2011 /*
2012 * Loop through the next chord's GRPSYLs to see if it has any
2013 * groups on this staff. If so, return our true RE, unless they are
2014 * not in danger of colliding.
2015 */
2016 for (ngs_p = nch_p->gs_p; ngs_p != 0; ngs_p = ngs_p->gs_p) {
2017 /* skip cases where there can't be any interference */
2018 if (ngs_p->staffno > gs_p->staffno)
2019 break; /* nothing more could be on our staff*/
2020 if (ngs_p->staffno < gs_p->staffno)
2021 continue; /* ignore if wrong staff */
2022 if (ngs_p->grpsyl == GS_SYLLABLE)
2023 continue; /* ignore if not a group */
2024 if (collision_danger(gs_p, ngs_p) == NO)
2025 continue;
2026
2027 /* found a group that might collide, return true RE */
2028 return (gs_p->c[RE]);
2029 }
2030
2031 return (small);
2032}
2033\f
2034/*
2035 * Name: collision_danger()
2036 *
2037 * Abstract: Find whether the given groups are in danger of colliding.
2038 *
2039 * Returns: YES or NO
2040 *
2041 * Description: This function is given two groups, a left and a right group,
2042 * that are on the same staff. If they are in the same voice, it
2043 * just returns YES (we don't want one note of a voice to go under
2044 * another in the same voice, and it would rarely work anyhow due
2045 * to stem directions). Otherwise it decides whether they are so
2046 * close vertically that they are in danger of colliding unless
2047 * kept apart horizontally.
2048 */
2049
2050static int
2051collision_danger(g1_p, g2_p)
2052
2053struct GRPSYL *g1_p; /* ptr to left group */
2054struct GRPSYL *g2_p; /* ptr to right group */
2055
2056{
2057 float staffscale;
2058 float stepsize; /* adjusted by staff scale */
2059 float north[2], south[2]; /* RN and RS of the groups */
2060 float dotoutside; /* RY just beyond outside edge of dot*/
2061 float ascent, descent; /* of an accidental */
2062 struct GRPSYL *g_p[2]; /* point at these two groups */
2063 int k, j; /* loop variables */
2064 float accedge; /* RN or RS of edge of accidental */
2065
2066
2067 /* same voice, always assume collideable */
2068 if (g1_p->vno == g2_p->vno) {
2069 return (YES);
2070 }
2071
2072 /* a space can't collide with anything */
2073 if (g1_p->grpcont == GC_SPACE || g2_p->grpcont == GC_SPACE) {
2074 return (NO);
2075 }
2076
2077 /* if measure repeat, there won't be anything else to collide with */
2078 if (is_mrpt(g1_p) || is_mrpt(g2_p)) {
2079 return (NO);
2080 }
2081
2082 staffscale = svpath(g1_p->staffno, STAFFSCALE)->staffscale;
2083 stepsize = STEPSIZE * staffscale;
2084 g_p[0] = g1_p;
2085 g_p[1] = g2_p;
2086
2087 /* find the RN and RS of the groups */
2088 for (k = 0; k < 2; k++) {
2089 if (g_p[k]->grpcont == GC_REST) {
2090 /* for rests, simply use the group boundaries */
2091 north[k] = g_p[k]->c[RN];
2092 south[k] = g_p[k]->c[RS];
2093
2094 /*
2095 * We can't use the group boundaries for notes. For one thing,
2096 * we don't know the stem length yet. Assume the worst, that
2097 * they are way long. It won't usually negatively impact the
2098 * result, nor will the fact that some notes don't have stems,
2099 * because most collisions would be on the non-stem side of the
2100 * groups. On the non-stem side, we can't use the group
2101 * boundary because it includes padding which would often make
2102 * it seem like there'd be a collision, when really there won't
2103 * be.
2104 */
2105 } else if (g_p[k]->stemdir == UP) {
2106
2107 north[k] = 10000.; /* way long stem */
2108
2109 /* one step below lowest note */
2110 south[k] = (g_p[k]->notelist[g_p[k]->nnotes-1].
2111 stepsup - 1) * stepsize;
2112
2113 /* if dots, and lower than current RS, lower the RS */
2114 if (k == 0 && g_p[k]->dots > 0) {
2115 dotoutside = g_p[k]->notelist[g_p[k]->nnotes-1].
2116 ydotr - 0.6 * stepsize;
2117 if (dotoutside < south[k]) {
2118 south[k] = dotoutside;
2119 }
2120 }
2121
2122 /* if any note has acc going below RS, lower the RS */
2123 if (k == 1) {
2124 for (j = 0; j < g_p[k]->nnotes; j++) {
2125 if (g_p[k]->notelist[j].accidental !=
2126 '\0') {
2127 accdimen(&g_p[k]->notelist[j],
2128 (float *)0, &descent,
2129 (float *)0);
2130 descent *= staffscale;
2131
2132 /* bottom edge of acc */
2133 accedge = stepsize *
2134 g_p[k]->notelist[j].stepsup -
2135 descent;
2136
2137 if (accedge < south[k]) {
2138 south[k] = accedge;
2139 }
2140 }
2141 }
2142 }
2143
2144 /* if bottom note has parens, the group boundary shows
2145 * close to how far down they go; extend to there */
2146 if (g_p[k]->notelist[g_p[k]->nnotes-1].note_has_paren
2147 && g_p[k]->c[RS] < south[k]) {
2148 south[k] = g_p[k]->c[RS];
2149 }
2150
2151 } else { /* stemdir == DOWN */
2152
2153 south[k] = -10000.; /* way long stem */
2154
2155 /* one step above highest note */
2156 north[k] = (g_p[k]->notelist[0].
2157 stepsup + 1) * stepsize;
2158
2159 /* if dots, and higher than current RN, raise the RN */
2160 if (k == 0 && g_p[k]->dots > 0) {
2161 dotoutside = g_p[k]->notelist[0].
2162 ydotr + 0.6 * stepsize;
2163 if (dotoutside > north[k]) {
2164 north[k] = dotoutside;
2165 }
2166 }
2167
2168 /* if any note has acc going above RN, raise the RN */
2169 if (k == 1) {
2170 for (j = 0; j < g_p[k]->nnotes; j++) {
2171 if (g_p[k]->notelist[j].accidental !=
2172 '\0') {
2173 accdimen(&g_p[k]->notelist[j],
2174 &ascent, (float *)0,
2175 (float *)0);
2176 ascent *= staffscale;
2177
2178 /* top edge of acc */
2179 accedge = stepsize *
2180 g_p[k]->notelist[j].stepsup +
2181 ascent;
2182
2183 if (accedge > north[k]) {
2184 north[k] = accedge;
2185 }
2186 }
2187 }
2188 }
2189
2190 /* if top note has parens, the group boundary shows
2191 * close to how far up they go; extend to there */
2192 if (g_p[k]->notelist[0].note_has_paren
2193 && g_p[k]->c[RN] > north[k]) {
2194 north[k] = g_p[k]->c[RN];
2195 }
2196 }
2197 }
2198
2199 /* if the groups don't overlap vertically, no collision danger */
2200 if (south[0] >= north[1] || north[0] <= south[1]) {
2201 return (NO);
2202 }
2203
2204 return (YES); /* collision danger */
2205}
2206\f
2207/*
2208 * Name: prevchord()
2209 *
2210 * Abstract: Find chord preceding the given one.
2211 *
2212 * Returns: pointer to previous chord, or 0 if none
2213 *
2214 * Description: This function is given a pointer to a chord headcell and a
2215 * chord in that list. It finds the preceding chord, returning
2216 * it, or 0 if none. If chord linked lists were doubly linked,
2217 * we wouldn't have to go through this aggravation.
2218 */
2219
2220static struct CHORD *
2221prevchord(mainll_p, ch_p)
2222
2223struct MAINLL *mainll_p; /* ptr to current syllable */
2224struct CHORD *ch_p; /* ptr to current chord */
2225
2226{
2227 register struct CHORD *prevch_p;
2228
2229
2230 prevch_p = mainll_p->u.chhead_p->ch_p; /* get first chord in list */
2231
2232 /* if current chord is first chord, there is none before it */
2233 if (prevch_p == ch_p)
2234 return (0);
2235
2236 /* loop until we find it, then return */
2237 while (prevch_p->ch_p != ch_p)
2238 prevch_p = prevch_p->ch_p;
2239 return (prevch_p);
2240}
2241\f
2242/*
2243 * Name: nextchsyl()
2244 *
2245 * Abstract: Find following syllable if it is in the next chord.
2246 *
2247 * Returns: pointer to next syllable, or 0 if none
2248 *
2249 * Description: This function is given a pointer to a syllable, and the chord
2250 * it is in. It looks in the next chord, to see if there is a
2251 * syllable there that follows this syllable. If there is, it
2252 * returns it. Otherwise it returns 0.
2253 * Note: if the next syllable is was given as a space, it counts
2254 * as if it weren't there at all (return 0).
2255 */
2256
2257static struct GRPSYL *
2258nextchsyl(gs_p, ch_p)
2259
2260struct GRPSYL *gs_p; /* ptr to current syllable */
2261struct CHORD *ch_p; /* ptr to current chord */
2262
2263{
2264 struct GRPSYL *nextgs_p; /* point, looking for next syl */
2265
2266
2267 /* if last chord in measure, return no next syllable */
2268 if (ch_p->ch_p == 0)
2269 return (0);
2270
2271 /*
2272 * Look down next chord until we hit either the end, or the syllable
2273 * that follows the given one. Return what was found.
2274 */
2275 for (nextgs_p = ch_p->ch_p->gs_p;
2276 nextgs_p != 0 && nextgs_p != gs_p->next;
2277 nextgs_p = nextgs_p->gs_p)
2278 ;
2279
2280 /* if syl doesn't exist or is a space, return 0 */
2281 if (nextgs_p == 0 || nextgs_p->syl == 0)
2282 return (0);
2283
2284 return (nextgs_p);
2285}
2286\f
2287/*
2288 * Name: prevchsyl()
2289 *
2290 * Abstract: Find preceding syllable if it is in the previous chord.
2291 *
2292 * Returns: pointer to previous syllable, or 0 if none
2293 *
2294 * Description: This function is given a pointer to a syllable, and the chord
2295 * it is in. It looks in the previous chord, to see if there is a
2296 * syllable there that precedes this syllable. If there is, it
2297 * returns it. Otherwise it returns 0.
2298 *
2299 * Note: if the prev syllable is given as a space, it counts
2300 * as if it weren't there at all (return 0).
2301 *
2302 * Also note: unlike nextchsyl, this function compares against
2303 * not only the given GRPSYL, but the also the previous GRPSYL.
2304 * It has to, because it is sometimes called with the previous
2305 * chord, and sometimes with the one before that.
2306 */
2307
2308static struct GRPSYL *
2309prevchsyl(gs_p, prevch_p)
2310
2311struct GRPSYL *gs_p; /* ptr to current syllable */
2312struct CHORD *prevch_p; /* ptr to previous chord */
2313
2314{
2315 struct GRPSYL *prevgs_p; /* point, looking for next syl */
2316
2317
2318 /* if first chord in measure, return no previous syllable */
2319 if (prevch_p == 0)
2320 return (0);
2321
2322 /*
2323 * Look down previous chord until we hit either the end, or the syllable
2324 * that precedes the given one. Return what was found.
2325 * "Precede" here means either directly precedes, or precedes in two
2326 * steps.
2327 */
2328 for (prevgs_p = prevch_p->gs_p;
2329 prevgs_p != 0 && ! (prevgs_p == gs_p->prev ||
2330 (gs_p->prev != 0 && prevgs_p == gs_p->prev->prev));
2331 prevgs_p = prevgs_p->gs_p)
2332 ;
2333
2334 /* if syl doesn't exist or is a space, return 0 */
2335 if (prevgs_p == 0 || prevgs_p->syl == 0)
2336 return (0);
2337
2338 return (prevgs_p);
2339}
2340\f
2341/*
2342 * Name: pedalroom()
2343 *
2344 * Abstract: Increase some chords' width to make room for pedal characters.
2345 *
2346 * Returns: void
2347 *
2348 * Description: This function tries to make room for "Ped." and "*", so that
2349 * they don't overwrite each other. For each "pedstar" style
2350 * pedal mark, it finds the chord it's closest to. If two of them
2351 * are on neighboring chords, it may widen the left chord to
2352 * provide enough room. The problem is, the best it can do is
2353 * assume that the pedal marks are exactly aligned with their
2354 * closest chords. It doesn't do anything about marks that are
2355 * not on neighboring chords, since that would be quite a bit
2356 * more work and would rarely be necessary. Worst of all, if two
2357 * marks' closest chords are the same chord, nothing can be done.
2358 */
2359
2360static void
2361pedalroom()
2362
2363{
2364 struct MAINLL *mainll_p; /* point at items in main linked list*/
2365 struct CHHEAD *chhead_p; /* point at a chord head cell */
2366 struct STAFF *staff_p; /* point at a staff */
2367 struct STUFF *stuff_p; /* point at a stuff */
2368 struct CHORD *pedch_p; /* point at a chord near a pedal mark*/
2369 struct CHORD *opedch_p; /* point at prev chord near pedal */
2370 int pedstyle; /* P_* */
2371 int pedchar, opedchar; /* current and previous pedal char */
2372 int font, size; /* of a pedal char */
2373 char *string; /* for pedal char */
2374 float needed; /* amount of room needed */
2375
2376
2377 debug(16, "pedalroom");
2378 initstructs();
2379
2380 chhead_p = 0; /* prevent useless 'used before set' warning */
2381
2382 /*
2383 * Loop down the main linked list looking for each chord list headcell.
2384 */
2385 for (mainll_p = Mainllhc_p; mainll_p != 0; mainll_p = mainll_p->next) {
2386
2387 switch (mainll_p->str) {
2388 case S_SSV:
2389 /* need to keep pedstyle and timeden up to date */
2390 asgnssv(mainll_p->u.ssv_p);
2391 continue; /* go to next MLL structure */
2392
2393 case S_CHHEAD:
2394 /* remember this measure's chord list */
2395 chhead_p = mainll_p->u.chhead_p;
2396 continue; /* go to next MLL structure */
2397
2398 case S_STAFF:
2399 pedstyle = svpath(mainll_p->u.staff_p->staffno,
2400 PEDSTYLE)->pedstyle;
2401 if (pedstyle != P_LINE) {
2402 staff_p = mainll_p->u.staff_p;
2403 break; /* break out and handle this */
2404 }
2405
2406 continue; /* not pedstar, ignore this staff */
2407
2408 default:
2409 continue; /* skip everything else */
2410 }
2411
2412 /*
2413 * At this point we are at a staff that has a pedstyle that
2414 * uses "Ped." and "*". Loop down the stuff list, looking for
2415 * pedal marks.
2416 */
2417 opedch_p = 0; /* no pedal mark yet in measure */
2418 opedchar = '\0';/* prevent useless 'used before set' warning */
2419 for (stuff_p = staff_p->stuff_p; stuff_p != 0;
2420 stuff_p = stuff_p->next) {
2421 /*
2422 * If it is not a pedal stuff, or it has no character,
2423 * like a continuation from the previous score, skip.
2424 */
2425 if (stuff_p->stuff_type != ST_PEDAL ||
2426 stuff_p->string == 0)
2427 continue;
2428 /*
2429 * Find the chord that is closest to this pedal mark,
2430 * and which character this pedal mark is.
2431 * But following the usual policy of applying "steps"
2432 * offsets only after everything else is done, we
2433 * ignore start.steps and use only start.count.
2434 */
2435 pedch_p = closestchord(stuff_p->start.count,
2436 chhead_p->ch_p);
2437 font = stuff_p->string[0];
2438 size = stuff_p->string[1];
2439 string = stuff_p->string + 2;
2440 pedchar = next_str_char(&string, &font, &size) & 0xff;
2441
2442 /* if first pedal mark in measure, nothing more to do*/
2443 if (opedch_p == 0) {
2444 /* remember as previous chord with pedal */
2445 opedch_p = pedch_p;
2446 opedchar = pedchar;
2447 continue;
2448 }
2449
2450 /*
2451 * If this pedal mark and the previous one are by
2452 * neighboring chords, assume these marks are exactly
2453 * aligned with their chords. Make sure the east half
2454 * of the previous chord plus the west half of this
2455 * chord is enough room for them. If it isn't, enlarge
2456 * the east half of the previous chord. (Note: RW is
2457 * negative, so it must be negated.)
2458 */
2459 if (pedch_p == opedch_p->ch_p) {
2460 needed = rightped(pedstyle, opedchar) +
2461 leftped(pedstyle, pedchar);
2462 if (stuff_p->all == YES) {
2463 needed *= Score.staffscale;
2464 } else {
2465 needed *= svpath(staff_p->staffno,
2466 STAFFSCALE)->staffscale;
2467 }
2468 if (opedch_p->c[RE] - pedch_p->c[RW] < needed){
2469 opedch_p->c[RE] = needed +
2470 pedch_p->c[RW];
2471 opedch_p->width = opedch_p->c[RE] -
2472 opedch_p->c[RW];
2473 }
2474 }
2475
2476 /* remember previous chord with pedal, and its char */
2477 opedch_p = pedch_p;
2478 opedchar = pedchar;
2479 }
2480 }
2481}
2482\f
2483/*
2484 * Name: closestchord()
2485 *
2486 * Abstract: Find closest chord to given time value.
2487 *
2488 * Returns: pointer to the closest chord
2489 *
2490 * Description: This function finds the CHORD in the given linked list that is
2491 * closest, timewise, to the given count number.
2492 */
2493
2494static struct CHORD *
2495closestchord(count, firstch_p)
2496
2497double count; /* which count of the measure */
2498struct CHORD *firstch_p; /* first CHORD in this measure */
2499
2500{
2501 RATIONAL reqtime; /* time requested */
2502 struct CHORD *ch_p; /* point along chord list */
2503 struct CHORD *och_p; /* (old) point along chord list */
2504
2505
2506 /* if at or before the first count, it's closest to first group */
2507 if (count <= 1)
2508 return (firstch_p);
2509
2510 /* get requested time to nearest tiny part of a count, in lowest terms*/
2511 reqtime.n = 4 * MAXBASICTIME * (count - 1) + 0.5;
2512 reqtime.d = 4 * MAXBASICTIME * Score.timeden;
2513 rred(&reqtime);
2514
2515 /*
2516 * Loop through the chord list. As soon as a chord starts at or after
2517 * the requested time value, check whether the requested time is closer
2518 * to the new chord's time, or the previous chord's. Return the
2519 * closest one.
2520 */
2521 for (och_p = firstch_p, ch_p = och_p->ch_p; ch_p != 0;
2522 och_p = ch_p, ch_p = ch_p->ch_p) {
2523 if (GE(ch_p->starttime, reqtime)) {
2524 if (GT( rsub(reqtime, och_p->starttime),
2525 rsub(ch_p->starttime, reqtime) ))
2526 return (ch_p);
2527 else
2528 return (och_p);
2529 }
2530 }
2531
2532 /* requested time is after last chord; return last chord */
2533 return (och_p);
2534}
2535\f
2536/*
2537 * Name: rightped()
2538 *
2539 * Abstract: Find the size of the right side of a pedstar pedal char.
2540 *
2541 * Returns: the size
2542 *
2543 * Description: This function finds the size of the part of the given pedal
2544 * character (pedstar style) that is to the right of where it
2545 * should be centered.
2546 */
2547
2548static double
2549rightped(pedstyle, pedchar)
2550
2551int pedstyle; /* pedstar or alt pedstar */
2552int pedchar; /* the given char */
2553
2554{
2555 switch (pedchar) {
2556 case C_BEGPED:
2557 return (strwidth(Ped_start) / 2.0);
2558 case C_PEDAL:
2559 if (pedstyle == P_PEDSTAR)
2560 return (strwidth(Ped_start) - ped_offset());
2561 else /* P_ALTPEDSTAR */
2562 return (strwidth(Ped_start) / 2.0);
2563 case C_ENDPED:
2564 return (strwidth(Ped_stop) / 2.0);
2565 default:
2566 pfatal("bad pedal character passed to rightped()");
2567 }
2568 return (0); /* to keep lint happy */
2569}
2570\f
2571/*
2572 * Name: leftped()
2573 *
2574 * Abstract: Find the size of the left side of a pedstar pedal char.
2575 *
2576 * Returns: the size
2577 *
2578 * Description: This function finds the size of the part of the given pedal
2579 * character (pedstar style) that is to the left of where it
2580 * should be centered.
2581 */
2582
2583static double
2584leftped(pedstyle, pedchar)
2585
2586int pedstyle; /* pedstar or alt pedstar */
2587int pedchar; /* the given char */
2588
2589{
2590 switch (pedchar) {
2591 case C_BEGPED:
2592 return (strwidth(Ped_start) / 2.0);
2593 case C_PEDAL:
2594 if (pedstyle == P_PEDSTAR)
2595 return (strwidth(Ped_stop) + ped_offset());
2596 else /* P_ALTPEDSTAR */
2597 return (strwidth(Ped_start) / 2.0);
2598 case C_ENDPED:
2599 return (strwidth(Ped_stop) / 2.0);
2600 default:
2601 pfatal("bad pedal character passed to leftped()");
2602 }
2603 return (0); /* to keep lint happy */
2604}
2605\f
2606/*
2607 * Name: fixspace()
2608 *
2609 * Abstract: Reset width, if need be, for chords of all spaces.
2610 *
2611 * Returns: void
2612 *
2613 * Description: This function loops through chord lists, looking for each chord
2614 * that is all spaces (as shown by the fact that its width is 0).
2615 * If any voice has a nonspace during the time value of this
2616 * chord, we reset its width to a very small positive number, to
2617 * prevent abshorz from treating it like it "deserves" no width
2618 * (rather than what its duration would imply).
2619 */
2620
2621static void
2622fixspace()
2623
2624{
2625 struct CHORD *ch_p; /* point at a chord */
2626 struct MAINLL *mainll_p; /* point at items in main linked list*/
2627 struct MAINLL *m2_p; /* another pointer down the MLL */
2628 int crunch; /* should chord be crunched to 0 width*/
2629 int v; /* voice number, 0 or 1 */
2630
2631
2632 debug(16, "fixspace");
2633 /*
2634 * Loop down the main linked list looking for each chord list headcell.
2635 */
2636 for (mainll_p = Mainllhc_p; mainll_p != 0; mainll_p = mainll_p->next) {
2637
2638 if (mainll_p->str != S_CHHEAD)
2639 continue; /* skip everything but chord HC */
2640
2641 /*
2642 * Loop through the chord list, looking for all-space chords.
2643 * Skip the first one in the list; we always want that one to
2644 * be crunched to zero width, since there's nothing earlier
2645 * that could extend into it.
2646 */
2647 for (ch_p = mainll_p->u.chhead_p->ch_p->ch_p; ch_p != 0;
2648 ch_p = ch_p->ch_p) {
2649
2650 if (ch_p->width != 0)
2651 continue; /* skip nonspace chord */
2652
2653 crunch = YES; /* init to crunch */
2654
2655 /* loop through every staff and every voice in meas */
2656 for (m2_p = mainll_p->next; m2_p->str == S_STAFF;
2657 m2_p = m2_p->next) {
2658
2659 for (v = 0; v < MAXVOICES && m2_p->u.staff_p->
2660 groups_p[v] != 0; v++) {
2661
2662 /* if voice has nonspace, don't crunch*/
2663 if ( ! hasspace(m2_p->u.staff_p->
2664 groups_p[v], ch_p->starttime,
2665 radd(ch_p->starttime, ch_p->duration))){
2666 crunch = NO;
2667 break;
2668 }
2669 }
2670
2671 if (crunch == NO)
2672 break;
2673 }
2674
2675 /* if should not crunch, set nonzero width to stop it */
2676 if (crunch == NO)
2677 ch_p->width = 0.001;
2678
2679 } /* for every chord in this measure */
2680
2681 } /* looping through MLL, dealing with chord headcells */
2682}